blob: 38a63faa7bf455b1f1d283bfd0b3db04a1818dd1 [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Mark Sleee9ce01c2007-05-16 02:29:53 +000019
David Reissbba69282009-02-17 20:28:28 +000020#include <string>
21#include <fstream>
22#include <iostream>
23#include <vector>
24
Mark Slee6e536442006-06-30 18:28:50 +000025#include <stdlib.h>
26#include <sys/stat.h>
27#include <sstream>
David Reissbba69282009-02-17 20:28:28 +000028#include "t_oop_generator.h"
David Reiss204420f2008-01-11 20:59:03 +000029#include "platform.h"
Mark Slee6e536442006-06-30 18:28:50 +000030using namespace std;
31
David Reissbba69282009-02-17 20:28:28 +000032
33/**
34 * PHP code generator.
35 *
David Reissbba69282009-02-17 20:28:28 +000036 */
37class t_php_generator : public t_oop_generator {
38 public:
39 t_php_generator(
40 t_program* program,
41 const std::map<std::string, std::string>& parsed_options,
42 const std::string& option_string)
43 : t_oop_generator(program)
44 {
45 std::map<std::string, std::string>::const_iterator iter;
46
47 iter = parsed_options.find("inlined");
48 binary_inline_ = (iter != parsed_options.end());
49
50 iter = parsed_options.find("rest");
51 rest_ = (iter != parsed_options.end());
52
53 iter = parsed_options.find("server");
54 phps_ = (iter != parsed_options.end());
55
56 iter = parsed_options.find("autoload");
57 autoload_ = (iter != parsed_options.end());
58
59 iter = parsed_options.find("oop");
60 oop_ = (iter != parsed_options.end());
61
62 if (oop_ && binary_inline_) {
63 throw "oop and inlined are mutually exclusive.";
64 }
65
66 out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php");
David Reiss82e6fc02009-03-26 23:32:36 +000067 escape_['$'] = "\\$";
David Reissbba69282009-02-17 20:28:28 +000068 }
69
70 /**
71 * Init and close methods
72 */
73
74 void init_generator();
75 void close_generator();
76
77 /**
78 * Program-level generation functions
79 */
80
81 void generate_typedef (t_typedef* ttypedef);
82 void generate_enum (t_enum* tenum);
83 void generate_const (t_const* tconst);
84 void generate_struct (t_struct* tstruct);
85 void generate_xception (t_struct* txception);
86 void generate_service (t_service* tservice);
87
88 std::string render_const_value(t_type* type, t_const_value* value);
89
90 /**
91 * Structs!
92 */
93
94 void generate_php_struct(t_struct* tstruct, bool is_exception);
95 void generate_php_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
96 void _generate_php_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
97 void generate_php_struct_reader(std::ofstream& out, t_struct* tstruct);
98 void generate_php_struct_writer(std::ofstream& out, t_struct* tstruct);
99 void generate_php_function_helpers(t_function* tfunction);
100
101 void generate_php_type_spec(std::ofstream &out, t_type* t);
102 void generate_php_struct_spec(std::ofstream &out, t_struct* tstruct);
103
104 /**
105 * Service-level generation functions
106 */
107
108 void generate_service_helpers (t_service* tservice);
109 void generate_service_interface (t_service* tservice);
110 void generate_service_rest (t_service* tservice);
111 void generate_service_client (t_service* tservice);
112 void _generate_service_client (std::ofstream &out, t_service* tservice);
113 void generate_service_processor (t_service* tservice);
114 void generate_process_function (t_service* tservice, t_function* tfunction);
115
116 /**
117 * Serialization constructs
118 */
119
120 void generate_deserialize_field (std::ofstream &out,
121 t_field* tfield,
122 std::string prefix="",
123 bool inclass=false);
124
125 void generate_deserialize_struct (std::ofstream &out,
126 t_struct* tstruct,
127 std::string prefix="");
128
129 void generate_deserialize_container (std::ofstream &out,
130 t_type* ttype,
131 std::string prefix="");
132
133 void generate_deserialize_set_element (std::ofstream &out,
134 t_set* tset,
135 std::string prefix="");
136
137 void generate_deserialize_map_element (std::ofstream &out,
138 t_map* tmap,
139 std::string prefix="");
140
141 void generate_deserialize_list_element (std::ofstream &out,
142 t_list* tlist,
143 std::string prefix="");
144
145 void generate_serialize_field (std::ofstream &out,
146 t_field* tfield,
147 std::string prefix="");
148
149 void generate_serialize_struct (std::ofstream &out,
150 t_struct* tstruct,
151 std::string prefix="");
152
153 void generate_serialize_container (std::ofstream &out,
154 t_type* ttype,
155 std::string prefix="");
156
157 void generate_serialize_map_element (std::ofstream &out,
158 t_map* tmap,
159 std::string kiter,
160 std::string viter);
161
162 void generate_serialize_set_element (std::ofstream &out,
163 t_set* tmap,
164 std::string iter);
165
166 void generate_serialize_list_element (std::ofstream &out,
167 t_list* tlist,
168 std::string iter);
169
170 /**
171 * Helper rendering functions
172 */
173
174 std::string php_includes();
175 std::string declare_field(t_field* tfield, bool init=false, bool obj=false);
176 std::string function_signature(t_function* tfunction, std::string prefix="");
177 std::string argument_list(t_struct* tstruct);
178 std::string type_to_cast(t_type* ttype);
179 std::string type_to_enum(t_type* ttype);
180
181 std::string php_namespace(t_program* p) {
David Reiss554ea6f2009-02-17 20:28:37 +0000182 std::string ns = p->get_namespace("php");
David Reissbba69282009-02-17 20:28:28 +0000183 return ns.size() ? (ns + "_") : "";
184 }
185
186 private:
187
188 /**
189 * File streams
190 */
191 std::ofstream f_types_;
192 std::ofstream f_consts_;
193 std::ofstream f_helpers_;
194 std::ofstream f_service_;
195
David Reissbb97bef2009-09-16 16:57:05 +0000196 std::string package_dir_;
David Reissbba69282009-02-17 20:28:28 +0000197 /**
198 * Generate protocol-independent template? Or Binary inline code?
199 */
200 bool binary_inline_;
201
202 /**
203 * Generate a REST handler class
204 */
205 bool rest_;
206
207 /**
208 * Generate stubs for a PHP server
209 */
210 bool phps_;
211
212 /**
213 * Generate PHP code that uses autoload
214 */
215 bool autoload_;
216
217 /**
218 * Whether to use OOP base class TBase
219 */
220 bool oop_;
221
222};
223
224
Mark Slee6e536442006-06-30 18:28:50 +0000225/**
226 * Prepares for file generation by opening up the necessary file output
227 * streams.
228 *
229 * @param tprogram The program to generate
230 */
Mark Sleef0712dc2006-10-25 19:03:57 +0000231void t_php_generator::init_generator() {
Mark Slee6e536442006-06-30 18:28:50 +0000232 // Make output directory
David Reiss204420f2008-01-11 20:59:03 +0000233 MKDIR(get_out_dir().c_str());
David Reissbb97bef2009-09-16 16:57:05 +0000234 package_dir_ = get_out_dir()+"/"+program_name_+"/";
235 MKDIR(package_dir_.c_str());
Mark Slee6e536442006-06-30 18:28:50 +0000236 // Make output file
David Reissbb97bef2009-09-16 16:57:05 +0000237 string f_types_name = package_dir_+program_name_+"_types.php";
Mark Slee6e536442006-06-30 18:28:50 +0000238 f_types_.open(f_types_name.c_str());
239
240 // Print header
241 f_types_ <<
242 "<?php" << endl <<
243 autogen_comment() <<
244 php_includes();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000245
Mark Slee5151c622007-11-06 22:11:29 +0000246 // Include other Thrift includes
247 const vector<t_program*>& includes = program_->get_includes();
248 for (size_t i = 0; i < includes.size(); ++i) {
Mark Slee5b743072007-11-13 04:00:29 +0000249 string package = includes[i]->get_name();
Mark Slee5151c622007-11-06 22:11:29 +0000250 f_types_ <<
Mark Slee5b743072007-11-13 04:00:29 +0000251 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << package << "/" << package << "_types.php';" << endl;
Mark Slee5151c622007-11-06 22:11:29 +0000252 }
253 f_types_ << endl;
254
Mark Sleeaa7671d2006-11-29 03:19:31 +0000255 // Print header
Mark Slee12a3b4e2007-11-20 02:05:29 +0000256 if (!program_->get_consts().empty()) {
David Reissbb97bef2009-09-16 16:57:05 +0000257 string f_consts_name = package_dir_+program_name_+"_constants.php";
Mark Slee12a3b4e2007-11-20 02:05:29 +0000258 f_consts_.open(f_consts_name.c_str());
259 f_consts_ <<
260 "<?php" << endl <<
261 autogen_comment() <<
262 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" + program_name_ + "/" + program_name_ + "_types.php';" << endl <<
263 endl <<
Christopher Piro21c95a32008-03-12 04:28:43 +0000264 "$GLOBALS['" << program_name_ << "_CONSTANTS'] = array();" << endl <<
Mark Slee12a3b4e2007-11-20 02:05:29 +0000265 endl;
266 }
Mark Slee6e536442006-06-30 18:28:50 +0000267}
268
269/**
peter67bfaf22007-05-01 04:03:22 +0000270 * Prints standard php includes
Mark Slee6e536442006-06-30 18:28:50 +0000271 */
272string t_php_generator::php_includes() {
273 return
Mark Slee1c4a5592006-09-25 21:32:05 +0000274 string("include_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';\n\n");
Mark Slee6e536442006-06-30 18:28:50 +0000275}
276
277/**
Mark Sleef5377b32006-10-10 01:42:59 +0000278 * Close up (or down) some filez.
Mark Slee6e536442006-06-30 18:28:50 +0000279 */
Mark Sleef0712dc2006-10-25 19:03:57 +0000280void t_php_generator::close_generator() {
Mark Slee6e536442006-06-30 18:28:50 +0000281 // Close types file
282 f_types_ << "?>" << endl;
283 f_types_.close();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000284
Mark Slee12a3b4e2007-11-20 02:05:29 +0000285 if (!program_->get_consts().empty()) {
286 f_consts_ << "?>" << endl;
287 f_consts_.close();
288 }
Mark Slee6e536442006-06-30 18:28:50 +0000289}
290
291/**
292 * Generates a typedef. This is not done in PHP, types are all implicit.
293 *
294 * @param ttypedef The type definition
295 */
296void t_php_generator::generate_typedef(t_typedef* ttypedef) {}
297
298/**
299 * Generates code for an enumerated type. Since define is expensive to lookup
300 * in PHP, we use a global array for this.
301 *
302 * @param tenum The enumeration
303 */
304void t_php_generator::generate_enum(t_enum* tenum) {
305 f_types_ <<
Mark Sleee888b372007-01-12 01:06:24 +0000306 "$GLOBALS['" << php_namespace(tenum->get_program()) << "E_" << tenum->get_name() << "'] = array(" << endl;
Mark Slee5151c622007-11-06 22:11:29 +0000307
Mark Slee30152872006-11-28 01:24:07 +0000308 vector<t_enum_value*> constants = tenum->get_constants();
309 vector<t_enum_value*>::iterator c_iter;
Mark Slee6e536442006-06-30 18:28:50 +0000310 int value = -1;
311 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
312 if ((*c_iter)->has_value()) {
313 value = (*c_iter)->get_value();
314 } else {
315 ++value;
316 }
317
318 f_types_ <<
319 " '" << (*c_iter)->get_name() << "' => " << value << "," << endl;
320 }
321
322 f_types_ <<
323 ");" << endl << endl;
324
325
326 // We're also doing it this way to see how it performs. It's more legible
327 // code but you can't do things like an 'extract' on it, which is a bit of
328 // a downer.
Mark Slee6e536442006-06-30 18:28:50 +0000329 f_types_ <<
Mark Sleee888b372007-01-12 01:06:24 +0000330 "final class " << php_namespace(tenum->get_program()) << tenum->get_name() << " {" << endl;
Mark Slee6e536442006-06-30 18:28:50 +0000331 indent_up();
Mark Slee5151c622007-11-06 22:11:29 +0000332
Mark Slee6e536442006-06-30 18:28:50 +0000333 value = -1;
334 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
335 if ((*c_iter)->has_value()) {
336 value = (*c_iter)->get_value();
337 } else {
338 ++value;
339 }
340
341 indent(f_types_) <<
342 "const " << (*c_iter)->get_name() << " = " << value << ";" << endl;
343 }
344
Mark Sleeec3f3202007-04-10 06:15:25 +0000345 indent(f_types_) <<
Mark Sleeb86c4b22007-04-10 06:44:53 +0000346 "static public $__names = array(" << endl;
Mark Sleeec3f3202007-04-10 06:15:25 +0000347 value = -1;
348 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
349 if ((*c_iter)->has_value()) {
350 value = (*c_iter)->get_value();
351 } else {
352 ++value;
353 }
354
355 indent(f_types_) <<
356 " " << value << " => '" << (*c_iter)->get_name() << "'," << endl;
357 }
358 indent(f_types_) <<
359 ");" << endl;
360
Mark Slee6e536442006-06-30 18:28:50 +0000361 indent_down();
362 f_types_ << "}" << endl << endl;
363}
364
Mark Sleef5377b32006-10-10 01:42:59 +0000365/**
Mark Sleeaa7671d2006-11-29 03:19:31 +0000366 * Generate a constant value
367 */
368void t_php_generator::generate_const(t_const* tconst) {
369 t_type* type = tconst->get_type();
370 string name = tconst->get_name();
371 t_const_value* value = tconst->get_value();
Mark Slee5151c622007-11-06 22:11:29 +0000372
373 f_consts_ << "$GLOBALS['" << program_name_ << "_CONSTANTS']['" << name << "'] = ";
Mark Slee7ff32452007-02-01 05:26:18 +0000374 f_consts_ << render_const_value(type, value);
Mark Sleeaa7671d2006-11-29 03:19:31 +0000375 f_consts_ << ";" << endl << endl;
376}
377
378/**
379 * Prints the value of a constant with the given type. Note that type checking
380 * is NOT performed in this function as it is always run beforehand using the
381 * validate_types method in main.cc
382 */
Mark Slee7ff32452007-02-01 05:26:18 +0000383string t_php_generator::render_const_value(t_type* type, t_const_value* value) {
384 std::ostringstream out;
David Reisse087a302007-08-23 21:43:25 +0000385 type = get_true_type(type);
Mark Sleeaa7671d2006-11-29 03:19:31 +0000386 if (type->is_base_type()) {
387 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
388 switch (tbase) {
389 case t_base_type::TYPE_STRING:
David Reiss82e6fc02009-03-26 23:32:36 +0000390 out << '"' << get_escaped_string(value) << '"';
Mark Sleeaa7671d2006-11-29 03:19:31 +0000391 break;
392 case t_base_type::TYPE_BOOL:
Mark Slee7ff32452007-02-01 05:26:18 +0000393 out << (value->get_integer() > 0 ? "true" : "false");
Mark Sleeaa7671d2006-11-29 03:19:31 +0000394 break;
395 case t_base_type::TYPE_BYTE:
396 case t_base_type::TYPE_I16:
397 case t_base_type::TYPE_I32:
398 case t_base_type::TYPE_I64:
Mark Slee7ff32452007-02-01 05:26:18 +0000399 out << value->get_integer();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000400 break;
401 case t_base_type::TYPE_DOUBLE:
402 if (value->get_type() == t_const_value::CV_INTEGER) {
Mark Slee7ff32452007-02-01 05:26:18 +0000403 out << value->get_integer();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000404 } else {
Mark Slee7ff32452007-02-01 05:26:18 +0000405 out << value->get_double();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000406 }
407 break;
408 default:
David Reissdd7796f2007-08-28 21:09:06 +0000409 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
Mark Sleeaa7671d2006-11-29 03:19:31 +0000410 }
411 } else if (type->is_enum()) {
Mark Slee7ff32452007-02-01 05:26:18 +0000412 indent(out) << value->get_integer();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000413 } else if (type->is_struct() || type->is_xception()) {
Mark Slee7ff32452007-02-01 05:26:18 +0000414 out << "new " << php_namespace(type->get_program()) << type->get_name() << "(array(" << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000415 indent_up();
416 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
417 vector<t_field*>::const_iterator f_iter;
418 const map<t_const_value*, t_const_value*>& val = value->get_map();
419 map<t_const_value*, t_const_value*>::const_iterator v_iter;
420 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
421 t_type* field_type = NULL;
422 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
423 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
424 field_type = (*f_iter)->get_type();
425 }
426 }
427 if (field_type == NULL) {
428 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
429 }
Mark Slee7ff32452007-02-01 05:26:18 +0000430 out << indent();
431 out << render_const_value(g_type_string, v_iter->first);
432 out << " => ";
433 out << render_const_value(field_type, v_iter->second);
434 out << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000435 }
436 indent_down();
Mark Slee7ff32452007-02-01 05:26:18 +0000437 indent(out) << "))";
Mark Sleeaa7671d2006-11-29 03:19:31 +0000438 } else if (type->is_map()) {
439 t_type* ktype = ((t_map*)type)->get_key_type();
440 t_type* vtype = ((t_map*)type)->get_val_type();
Mark Slee7ff32452007-02-01 05:26:18 +0000441 out << "array(" << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000442 indent_up();
443 const map<t_const_value*, t_const_value*>& val = value->get_map();
444 map<t_const_value*, t_const_value*>::const_iterator v_iter;
445 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
Mark Slee7ff32452007-02-01 05:26:18 +0000446 out << indent();
447 out << render_const_value(ktype, v_iter->first);
448 out << " => ";
449 out << render_const_value(vtype, v_iter->second);
450 out << "," << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000451 }
452 indent_down();
Mark Slee7ff32452007-02-01 05:26:18 +0000453 indent(out) << ")";
Mark Sleeaa7671d2006-11-29 03:19:31 +0000454 } else if (type->is_list() || type->is_set()) {
455 t_type* etype;
456 if (type->is_list()) {
457 etype = ((t_list*)type)->get_elem_type();
458 } else {
459 etype = ((t_set*)type)->get_elem_type();
460 }
Mark Slee7ff32452007-02-01 05:26:18 +0000461 out << "array(" << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000462 indent_up();
463 const vector<t_const_value*>& val = value->get_list();
464 vector<t_const_value*>::const_iterator v_iter;
465 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
Mark Slee7ff32452007-02-01 05:26:18 +0000466 out << indent();
467 out << render_const_value(etype, *v_iter);
Mark Slee600cdb32006-11-29 22:06:42 +0000468 if (type->is_set()) {
Mark Slee7ff32452007-02-01 05:26:18 +0000469 out << " => true";
Mark Slee600cdb32006-11-29 22:06:42 +0000470 }
Mark Slee7ff32452007-02-01 05:26:18 +0000471 out << "," << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000472 }
473 indent_down();
Mark Slee7ff32452007-02-01 05:26:18 +0000474 indent(out) << ")";
Mark Sleeaa7671d2006-11-29 03:19:31 +0000475 }
Mark Slee7ff32452007-02-01 05:26:18 +0000476 return out.str();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000477}
478
479/**
Mark Sleef5377b32006-10-10 01:42:59 +0000480 * Make a struct
481 */
Mark Slee9cb7c612006-09-01 22:17:45 +0000482void t_php_generator::generate_struct(t_struct* tstruct) {
483 generate_php_struct(tstruct, false);
484}
485
486/**
487 * Generates a struct definition for a thrift exception. Basically the same
488 * as a struct but extends the Exception class.
489 *
490 * @param txception The struct definition
491 */
492void t_php_generator::generate_xception(t_struct* txception) {
Mark Slee5151c622007-11-06 22:11:29 +0000493 generate_php_struct(txception, true);
Mark Slee9cb7c612006-09-01 22:17:45 +0000494}
495
Mark Sleef5377b32006-10-10 01:42:59 +0000496/**
497 * Structs can be normal or exceptions.
498 */
Mark Slee9cb7c612006-09-01 22:17:45 +0000499void t_php_generator::generate_php_struct(t_struct* tstruct,
500 bool is_exception) {
501 generate_php_struct_definition(f_types_, tstruct, is_exception);
Mark Slee9cb7c612006-09-01 22:17:45 +0000502}
503
Mark Slee5b743072007-11-13 04:00:29 +0000504void t_php_generator::generate_php_type_spec(ofstream& out,
505 t_type* t) {
506 t = get_true_type(t);
507 indent(out) << "'type' => " << type_to_enum(t) << "," << endl;
508
509 if (t->is_base_type() || t->is_enum()) {
510 // Noop, type is all we need
511 } else if (t->is_struct() || t->is_xception()) {
Mark Sleec557df42007-11-13 05:53:44 +0000512 indent(out) << "'class' => '" << php_namespace(t->get_program()) << t->get_name() <<"'," << endl;
Mark Slee5b743072007-11-13 04:00:29 +0000513 } else if (t->is_map()) {
514 t_type* ktype = get_true_type(((t_map*)t)->get_key_type());
515 t_type* vtype = get_true_type(((t_map*)t)->get_val_type());
516 indent(out) << "'ktype' => " << type_to_enum(ktype) << "," << endl;
517 indent(out) << "'vtype' => " << type_to_enum(vtype) << "," << endl;
518 indent(out) << "'key' => array(" << endl;
519 indent_up();
520 generate_php_type_spec(out, ktype);
521 indent_down();
522 indent(out) << ")," << endl;
523 indent(out) << "'val' => array(" << endl;
524 indent_up();
525 generate_php_type_spec(out, vtype);
526 indent(out) << ")," << endl;
527 indent_down();
528 } else if (t->is_list() || t->is_set()) {
529 t_type* etype;
530 if (t->is_list()) {
531 etype = get_true_type(((t_list*)t)->get_elem_type());
532 } else {
533 etype = get_true_type(((t_set*)t)->get_elem_type());
534 }
535 indent(out) << "'etype' => " << type_to_enum(etype) <<"," << endl;
536 indent(out) << "'elem' => array(" << endl;
537 indent_up();
538 generate_php_type_spec(out, etype);
539 indent(out) << ")," << endl;
540 indent_down();
541 } else {
542 throw "compiler error: no type for php struct spec field";
543 }
544
545}
546
547/**
548 * Generates the struct specification structure, which fully qualifies enough
549 * type information to generalize serialization routines.
550 */
551void t_php_generator::generate_php_struct_spec(ofstream& out,
552 t_struct* tstruct) {
Mark Slee89d52072007-11-14 00:24:14 +0000553 indent(out) << "if (!isset(self::$_TSPEC)) {" << endl;
554 indent_up();
555
556 indent(out) << "self::$_TSPEC = array(" << endl;
Mark Slee5b743072007-11-13 04:00:29 +0000557 indent_up();
558
559 const vector<t_field*>& members = tstruct->get_members();
560 vector<t_field*>::const_iterator m_iter;
561 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
562 t_type* t = get_true_type((*m_iter)->get_type());
563 indent(out) << (*m_iter)->get_key() << " => array(" << endl;
564 indent_up();
565 out <<
566 indent() << "'var' => '" << (*m_iter)->get_name() << "'," << endl;
567 generate_php_type_spec(out, t);
568 indent(out) << ")," << endl;
569 indent_down();
570 }
571
572 indent_down();
573 indent(out) << " );" << endl;
Mark Slee89d52072007-11-14 00:24:14 +0000574 indent_down();
575 indent(out) << "}" << endl;
Mark Slee5b743072007-11-13 04:00:29 +0000576}
577
578
Mark Slee09f69e02007-11-17 00:32:36 +0000579void t_php_generator::generate_php_struct_definition(ofstream& out,
580 t_struct* tstruct,
581 bool is_exception) {
582 if (autoload_) {
583 // Make output file
584 ofstream autoload_out;
585 string f_struct = program_name_+"."+(tstruct->get_name())+".php";
David Reissbb97bef2009-09-16 16:57:05 +0000586 string f_struct_name = package_dir_+f_struct;
Mark Slee09f69e02007-11-17 00:32:36 +0000587 autoload_out.open(f_struct_name.c_str());
588 autoload_out << "<?php" << endl;
589 _generate_php_struct_definition(autoload_out, tstruct, is_exception);
590 autoload_out << endl << "?>" << endl;
591 autoload_out.close();
592
593 f_types_ <<
Mark Sleee02ab332007-11-28 04:17:49 +0000594 "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(php_namespace(tstruct->get_program()) + tstruct->get_name()) << "'] = '" << program_name_ << "/" << f_struct << "';" << endl;
Mark Slee09f69e02007-11-17 00:32:36 +0000595
596 } else {
597 _generate_php_struct_definition(out, tstruct, is_exception);
598 }
599}
600
Mark Slee6e536442006-06-30 18:28:50 +0000601/**
602 * Generates a struct definition for a thrift data type. This is nothing in PHP
603 * where the objects are all just associative arrays (unless of course we
604 * decide to start using objects for them...)
605 *
606 * @param tstruct The struct definition
607 */
Mark Slee09f69e02007-11-17 00:32:36 +0000608void t_php_generator::_generate_php_struct_definition(ofstream& out,
Mark Slee9cb7c612006-09-01 22:17:45 +0000609 t_struct* tstruct,
610 bool is_exception) {
Mark Slee6e536442006-06-30 18:28:50 +0000611 const vector<t_field*>& members = tstruct->get_members();
Mark Slee5151c622007-11-06 22:11:29 +0000612 vector<t_field*>::const_iterator m_iter;
Mark Slee9cb7c612006-09-01 22:17:45 +0000613
614 out <<
Mark Sleee888b372007-01-12 01:06:24 +0000615 "class " << php_namespace(tstruct->get_program()) << tstruct->get_name();
Mark Slee9cb7c612006-09-01 22:17:45 +0000616 if (is_exception) {
Mark Slee5b743072007-11-13 04:00:29 +0000617 out << " extends TException";
Mark Sleeb22df7c2007-11-28 02:39:59 +0000618 } else if (oop_) {
Mark Slee5b743072007-11-13 04:00:29 +0000619 out << " extends TBase";
Mark Slee9cb7c612006-09-01 22:17:45 +0000620 }
621 out <<
622 " {" << endl;
623 indent_up();
624
dweatherfordcf997a42008-03-04 01:08:23 +0000625 indent(out) << "static $_TSPEC;" << endl << endl;
Mark Slee5b743072007-11-13 04:00:29 +0000626
Mark Slee6e536442006-06-30 18:28:50 +0000627 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
Mark Slee7ff32452007-02-01 05:26:18 +0000628 string dval = "null";
David Reisse087a302007-08-23 21:43:25 +0000629 t_type* t = get_true_type((*m_iter)->get_type());
Mark Slee7ff32452007-02-01 05:26:18 +0000630 if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
631 dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
632 }
Mark Slee9cb7c612006-09-01 22:17:45 +0000633 indent(out) <<
Mark Slee7ff32452007-02-01 05:26:18 +0000634 "public $" << (*m_iter)->get_name() << " = " << dval << ";" << endl;
Mark Slee6e536442006-06-30 18:28:50 +0000635 }
Mark Slee5151c622007-11-06 22:11:29 +0000636
Mark Sleeb7f58ff2006-09-02 21:59:28 +0000637 out << endl;
Mark Slee6e536442006-06-30 18:28:50 +0000638
Mark Slee216e7d62006-11-21 00:44:23 +0000639 // Generate constructor from array
dweatherfordcf997a42008-03-04 01:08:23 +0000640 string param = (members.size() > 0) ? "$vals=null" : "";
641 out <<
642 indent() << "public function __construct(" << param << ") {" << endl;
643 indent_up();
644
645 generate_php_struct_spec(out, tstruct);
646
647 if (members.size() > 0) {
648 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
649 t_type* t = get_true_type((*m_iter)->get_type());
650 if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
651 indent(out) << "$this->" << (*m_iter)->get_name() << " = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
652 }
653 }
Mark Slee216e7d62006-11-21 00:44:23 +0000654 out <<
dweatherfordcf997a42008-03-04 01:08:23 +0000655 indent() << "if (is_array($vals)) {" << endl;
Mark Sleeb22df7c2007-11-28 02:39:59 +0000656 indent_up();
Mark Sleeb22df7c2007-11-28 02:39:59 +0000657 if (oop_) {
Mark Sleedcdf25b2008-03-19 20:16:35 +0000658 out << indent() << "parent::__construct(self::$_TSPEC, $vals);" << endl;
dweatherfordcf997a42008-03-04 01:08:23 +0000659 } else {
Mark Sleeb22df7c2007-11-28 02:39:59 +0000660 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
dweatherfordcf997a42008-03-04 01:08:23 +0000661 out <<
662 indent() << "if (isset($vals['" << (*m_iter)->get_name() << "'])) {" << endl <<
663 indent() << " $this->" << (*m_iter)->get_name() << " = $vals['" << (*m_iter)->get_name() << "'];" << endl <<
664 indent() << "}" << endl;
Mark Sleeb22df7c2007-11-28 02:39:59 +0000665 }
Mark Sleeb22df7c2007-11-28 02:39:59 +0000666 }
dweatherfordcf997a42008-03-04 01:08:23 +0000667 indent_down();
668 out <<
669 indent() << "}" << endl;
Mark Slee19e71c32006-11-10 23:07:35 +0000670 }
dweatherfordcf997a42008-03-04 01:08:23 +0000671 scope_down(out);
672 out << endl;
Mark Slee5151c622007-11-06 22:11:29 +0000673
Mark Slee86c87b02007-02-06 07:11:23 +0000674 out <<
675 indent() << "public function getName() {" << endl <<
676 indent() << " return '" << tstruct->get_name() << "';" << endl <<
677 indent() << "}" << endl <<
678 endl;
Mark Slee5151c622007-11-06 22:11:29 +0000679
Mark Sleeb7f58ff2006-09-02 21:59:28 +0000680 generate_php_struct_reader(out, tstruct);
681 generate_php_struct_writer(out, tstruct);
682
683 indent_down();
Mark Slee9cb7c612006-09-01 22:17:45 +0000684 out <<
685 indent() << "}" << endl <<
686 endl;
687}
688
Mark Sleef5377b32006-10-10 01:42:59 +0000689/**
690 * Generates the read() method for a struct
691 */
Mark Slee9cb7c612006-09-01 22:17:45 +0000692void t_php_generator::generate_php_struct_reader(ofstream& out,
693 t_struct* tstruct) {
694 const vector<t_field*>& fields = tstruct->get_members();
695 vector<t_field*>::const_iterator f_iter;
696
Mark Slee5f8237d2006-10-26 04:57:03 +0000697 indent(out) <<
Mark Slee5b743072007-11-13 04:00:29 +0000698 "public function read($input)" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000699 scope_up(out);
700
Mark Sleeb22df7c2007-11-28 02:39:59 +0000701 if (oop_) {
702 indent(out) << "return $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);" << endl;
703 scope_down(out);
704 return;
705 }
Mark Slee5b743072007-11-13 04:00:29 +0000706
Mark Slee9cb7c612006-09-01 22:17:45 +0000707 out <<
708 indent() << "$xfer = 0;" << endl <<
709 indent() << "$fname = null;" << endl <<
710 indent() << "$ftype = 0;" << endl <<
711 indent() << "$fid = 0;" << endl;
712
713 // Declare stack tmp variables
714 if (!binary_inline_) {
715 indent(out) <<
Mark Slee5151c622007-11-06 22:11:29 +0000716 "$xfer += $input->readStructBegin($fname);" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000717 }
718
719 // Loop over reading in fields
720 indent(out) <<
721 "while (true)" << endl;
722
723 scope_up(out);
Mark Slee5151c622007-11-06 22:11:29 +0000724
Mark Slee9cb7c612006-09-01 22:17:45 +0000725 // Read beginning field marker
726 if (binary_inline_) {
Mark Sleef0712dc2006-10-25 19:03:57 +0000727 t_field fftype(g_type_byte, "ftype");
728 t_field ffid(g_type_i16, "fid");
Mark Slee9cb7c612006-09-01 22:17:45 +0000729 generate_deserialize_field(out, &fftype);
730 out <<
731 indent() << "if ($ftype == TType::STOP) {" << endl <<
732 indent() << " break;" << endl <<
Mark Slee5151c622007-11-06 22:11:29 +0000733 indent() << "}" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000734 generate_deserialize_field(out, &ffid);
735 } else {
736 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000737 "$xfer += $input->readFieldBegin($fname, $ftype, $fid);" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000738 // Check for field STOP marker and break
739 indent(out) <<
740 "if ($ftype == TType::STOP) {" << endl;
741 indent_up();
742 indent(out) <<
743 "break;" << endl;
744 indent_down();
745 indent(out) <<
746 "}" << endl;
Mark Slee5151c622007-11-06 22:11:29 +0000747 }
748
Mark Slee9cb7c612006-09-01 22:17:45 +0000749 // Switch statement on the field we are reading
750 indent(out) <<
751 "switch ($fid)" << endl;
752
753 scope_up(out);
Mark Slee5151c622007-11-06 22:11:29 +0000754
Mark Slee9cb7c612006-09-01 22:17:45 +0000755 // Generate deserialization code for known cases
756 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
757 indent(out) <<
758 "case " << (*f_iter)->get_key() << ":" << endl;
759 indent_up();
Mark Slee2006d992007-01-29 17:58:54 +0000760 indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
761 indent_up();
Mark Sleeb7f58ff2006-09-02 21:59:28 +0000762 generate_deserialize_field(out, *f_iter, "this->");
Mark Slee2006d992007-01-29 17:58:54 +0000763 indent_down();
764 out <<
765 indent() << "} else {" << endl;
766 if (binary_inline_) {
767 indent(out) << " $xfer += TProtocol::skipBinary($input, $ftype);" << endl;
768 } else {
769 indent(out) << " $xfer += $input->skip($ftype);" << endl;
770 }
Mark Slee5151c622007-11-06 22:11:29 +0000771 out <<
Mark Slee2006d992007-01-29 17:58:54 +0000772 indent() << "}" << endl <<
773 indent() << "break;" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000774 indent_down();
775 }
Mark Slee5151c622007-11-06 22:11:29 +0000776
Mark Slee9cb7c612006-09-01 22:17:45 +0000777 // In the default case we skip the field
Mark Sleef5377b32006-10-10 01:42:59 +0000778 indent(out) << "default:" << endl;
779 if (binary_inline_) {
Mark Slee5f8237d2006-10-26 04:57:03 +0000780 indent(out) << " $xfer += TProtocol::skipBinary($input, $ftype);" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +0000781 } else {
Mark Slee5f8237d2006-10-26 04:57:03 +0000782 indent(out) << " $xfer += $input->skip($ftype);" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +0000783 }
784 indent(out) << " break;" << endl;
Mark Slee5151c622007-11-06 22:11:29 +0000785
Mark Slee9cb7c612006-09-01 22:17:45 +0000786 scope_down(out);
Mark Slee5151c622007-11-06 22:11:29 +0000787
Mark Slee9cb7c612006-09-01 22:17:45 +0000788 if (!binary_inline_) {
789 // Read field end marker
790 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000791 "$xfer += $input->readFieldEnd();" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000792 }
Mark Slee5151c622007-11-06 22:11:29 +0000793
Mark Slee9cb7c612006-09-01 22:17:45 +0000794 scope_down(out);
Mark Slee5151c622007-11-06 22:11:29 +0000795
Mark Slee9cb7c612006-09-01 22:17:45 +0000796 if (!binary_inline_) {
797 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000798 "$xfer += $input->readStructEnd();" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000799 }
800
801 indent(out) <<
802 "return $xfer;" << endl;
803
804 indent_down();
805 out <<
806 indent() << "}" << endl <<
807 endl;
808}
809
Mark Sleef5377b32006-10-10 01:42:59 +0000810/**
811 * Generates the write() method for a struct
812 */
Mark Slee9cb7c612006-09-01 22:17:45 +0000813void t_php_generator::generate_php_struct_writer(ofstream& out,
814 t_struct* tstruct) {
815 string name = tstruct->get_name();
Bryan Duxburyff219ac2009-04-10 21:51:00 +0000816 const vector<t_field*>& fields = tstruct->get_sorted_members();
Mark Slee9cb7c612006-09-01 22:17:45 +0000817 vector<t_field*>::const_iterator f_iter;
818
819 if (binary_inline_) {
820 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000821 "public function write(&$output) {" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000822 } else {
823 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000824 "public function write($output) {" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000825 }
826 indent_up();
Mark Slee5151c622007-11-06 22:11:29 +0000827
Mark Sleeb22df7c2007-11-28 02:39:59 +0000828 if (oop_) {
829 indent(out) << "return $this->_write('" << tstruct->get_name() << "', self::$_TSPEC, $output);" << endl;
830 scope_down(out);
831 return;
832 }
Mark Slee5b743072007-11-13 04:00:29 +0000833
Mark Slee9cb7c612006-09-01 22:17:45 +0000834 indent(out) <<
835 "$xfer = 0;" << endl;
836
837 if (!binary_inline_) {
838 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000839 "$xfer += $output->writeStructBegin('" << name << "');" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000840 }
841
Mark Slee5151c622007-11-06 22:11:29 +0000842 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
Mark Sleef5377b32006-10-10 01:42:59 +0000843 out <<
844 indent() << "if ($this->" << (*f_iter)->get_name() << " !== null) {" << endl;
845 indent_up();
846
David Reissc0092f92008-06-10 22:55:46 +0000847 t_type* type = get_true_type((*f_iter)->get_type());
848 string expect;
849 if (type->is_container()) {
850 expect = "array";
851 } else if (type->is_struct()) {
852 expect = "object";
853 }
854 if (!expect.empty()) {
855 out <<
856 indent() << "if (!is_" << expect << "($this->" << (*f_iter)->get_name() << ")) {" << endl;
857 indent_up();
858 out <<
859 indent() << "throw new TProtocolException('Bad type in structure.', TProtocolException::INVALID_DATA);" << endl;
860 scope_down(out);
861 }
862
Mark Slee9cb7c612006-09-01 22:17:45 +0000863 // Write field header
864 if (binary_inline_) {
865 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000866 indent() << "$output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");" << endl <<
867 indent() << "$output .= pack('n', " << (*f_iter)->get_key() << ");" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000868 } else {
869 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000870 "$xfer += $output->writeFieldBegin(" <<
Mark Slee9cb7c612006-09-01 22:17:45 +0000871 "'" << (*f_iter)->get_name() << "', " <<
872 type_to_enum((*f_iter)->get_type()) << ", " <<
873 (*f_iter)->get_key() << ");" << endl;
874 }
875
876 // Write field contents
Mark Sleeb7f58ff2006-09-02 21:59:28 +0000877 generate_serialize_field(out, *f_iter, "this->");
Mark Slee9cb7c612006-09-01 22:17:45 +0000878
879 // Write field closer
880 if (!binary_inline_) {
881 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000882 "$xfer += $output->writeFieldEnd();" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000883 }
Mark Sleef5377b32006-10-10 01:42:59 +0000884
885 indent_down();
886 indent(out) <<
887 "}" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000888 }
889
890 if (binary_inline_) {
891 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000892 indent() << "$output .= pack('c', TType::STOP);" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000893 } else {
Mark Slee9cb7c612006-09-01 22:17:45 +0000894 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000895 indent() << "$xfer += $output->writeFieldStop();" << endl <<
896 indent() << "$xfer += $output->writeStructEnd();" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +0000897 }
898
899 out <<
900 indent() << "return $xfer;" << endl;
901
902 indent_down();
903 out <<
Mark Slee6e536442006-06-30 18:28:50 +0000904 indent() << "}" << endl <<
905 endl;
906}
907
908/**
Mark Slee9cb7c612006-09-01 22:17:45 +0000909 * Generates a thrift service.
Mark Slee6e536442006-06-30 18:28:50 +0000910 *
911 * @param tservice The service definition
912 */
913void t_php_generator::generate_service(t_service* tservice) {
David Reissbb97bef2009-09-16 16:57:05 +0000914 string f_service_name = package_dir_+service_name_+".php";
Mark Slee6e536442006-06-30 18:28:50 +0000915 f_service_.open(f_service_name.c_str());
916
917 f_service_ <<
918 "<?php" << endl <<
919 autogen_comment() <<
920 php_includes();
921
922 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +0000923 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << program_name_ << "/" << program_name_ << "_types.php';" << endl;
924
925 if (tservice->get_extends() != NULL) {
926 f_service_ <<
927 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << tservice->get_extends()->get_program()->get_name() << "/" << tservice->get_extends()->get_name() << ".php';" << endl;
928 }
Mark Slee5151c622007-11-06 22:11:29 +0000929
Mark Sleef0712dc2006-10-25 19:03:57 +0000930 f_service_ <<
931 endl;
Mark Slee6e536442006-06-30 18:28:50 +0000932
933 // Generate the three main parts of the service (well, two for now in PHP)
934 generate_service_interface(tservice);
Mark Slee756b1d12007-07-06 00:30:21 +0000935 if (rest_) {
936 generate_service_rest(tservice);
937 }
Mark Slee6e536442006-06-30 18:28:50 +0000938 generate_service_client(tservice);
Mark Slee9cb7c612006-09-01 22:17:45 +0000939 generate_service_helpers(tservice);
Mark Slee5b743072007-11-13 04:00:29 +0000940 if (phps_) {
941 generate_service_processor(tservice);
942 }
Mark Slee5151c622007-11-06 22:11:29 +0000943
Mark Slee6e536442006-06-30 18:28:50 +0000944 // Close service file
945 f_service_ << "?>" << endl;
946 f_service_.close();
947}
948
949/**
Mark Sleef5377b32006-10-10 01:42:59 +0000950 * Generates a service server definition.
951 *
952 * @param tservice The service to generate a server for.
953 */
954void t_php_generator::generate_service_processor(t_service* tservice) {
955 // Generate the dispatch methods
956 vector<t_function*> functions = tservice->get_functions();
Mark Slee5151c622007-11-06 22:11:29 +0000957 vector<t_function*>::iterator f_iter;
Mark Sleef5377b32006-10-10 01:42:59 +0000958
Mark Sleef0712dc2006-10-25 19:03:57 +0000959 string extends = "";
960 string extends_processor = "";
961 if (tservice->get_extends() != NULL) {
962 extends = tservice->get_extends()->get_name();
963 extends_processor = " extends " + extends + "Processor";
964 }
965
Mark Sleef5377b32006-10-10 01:42:59 +0000966 // Generate the header portion
967 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +0000968 "class " << service_name_ << "Processor" << extends_processor << " {" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +0000969 indent_up();
970
Mark Sleef0712dc2006-10-25 19:03:57 +0000971 if (extends.empty()) {
972 f_service_ <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000973 indent() << "protected $handler_ = null;" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +0000974 }
975
Mark Slee5f8237d2006-10-26 04:57:03 +0000976 f_service_ <<
977 indent() << "public function __construct($handler) {" << endl;
978 if (extends.empty()) {
Mark Sleef5377b32006-10-10 01:42:59 +0000979 f_service_ <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000980 indent() << " $this->handler_ = $handler;" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +0000981 } else {
982 f_service_ <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000983 indent() << " parent::__construct($handler);" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +0000984 }
Mark Slee5f8237d2006-10-26 04:57:03 +0000985 f_service_ <<
986 indent() << "}" << endl <<
987 endl;
Mark Sleef5377b32006-10-10 01:42:59 +0000988
989 // Generate the server implementation
990 indent(f_service_) <<
Mark Slee5f8237d2006-10-26 04:57:03 +0000991 "public function process($input, $output) {" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +0000992 indent_up();
993
994 f_service_ <<
995 indent() << "$rseqid = 0;" << endl <<
996 indent() << "$fname = null;" << endl <<
997 indent() << "$mtype = 0;" << endl <<
998 endl;
999
1000 if (binary_inline_) {
Mark Sleef0712dc2006-10-25 19:03:57 +00001001 t_field ffname(g_type_string, "fname");
1002 t_field fmtype(g_type_byte, "mtype");
1003 t_field fseqid(g_type_i32, "rseqid");
Mark Sleef5377b32006-10-10 01:42:59 +00001004 generate_deserialize_field(f_service_, &ffname, "", true);
1005 generate_deserialize_field(f_service_, &fmtype, "", true);
1006 generate_deserialize_field(f_service_, &fseqid, "", true);
1007 } else {
1008 f_service_ <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001009 indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +00001010 }
1011
Mark Sleef5377b32006-10-10 01:42:59 +00001012 // HOT: check for method implementation
1013 f_service_ <<
Mark Slee5151c622007-11-06 22:11:29 +00001014 indent() << "$methodname = 'process_'.$fname;" << endl <<
Mark Slee7a498882007-02-27 22:11:39 +00001015 indent() << "if (!method_exists($this, $methodname)) {" << endl;
1016 if (binary_inline_) {
1017 f_service_ <<
1018 indent() << " throw new Exception('Function '.$fname.' not implemented.');" << endl;
1019 } else {
1020 f_service_ <<
1021 indent() << " $input->skip(TType::STRUCT);" << endl <<
1022 indent() << " $input->readMessageEnd();" << endl <<
1023 indent() << " $x = new TApplicationException('Function '.$fname.' not implemented.', TApplicationException::UNKNOWN_METHOD);" << endl <<
1024 indent() << " $output->writeMessageBegin($fname, TMessageType::EXCEPTION, $rseqid);" << endl <<
1025 indent() << " $x->write($output);" << endl <<
1026 indent() << " $output->writeMessageEnd();" << endl <<
1027 indent() << " $output->getTransport()->flush();" << endl <<
1028 indent() << " return;" << endl;
1029 }
1030 f_service_ <<
Mark Sleef5377b32006-10-10 01:42:59 +00001031 indent() << "}" << endl <<
Mark Slee7a498882007-02-27 22:11:39 +00001032 indent() << "$this->$methodname($rseqid, $input, $output);" << endl <<
1033 indent() << "return true;" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +00001034 indent_down();
1035 f_service_ <<
1036 indent() << "}" << endl <<
1037 endl;
1038
1039 // Generate the process subfunctions
1040 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1041 generate_process_function(tservice, *f_iter);
1042 }
1043
1044 indent_down();
1045 f_service_ << "}" << endl;
1046}
1047
1048/**
1049 * Generates a process function definition.
1050 *
1051 * @param tfunction The function to write a dispatcher for
1052 */
1053void t_php_generator::generate_process_function(t_service* tservice,
1054 t_function* tfunction) {
1055 // Open function
1056 indent(f_service_) <<
Mark Slee98e962b2007-02-20 18:44:05 +00001057 "protected function process_" << tfunction->get_name() <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001058 "($seqid, $input, $output) {" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +00001059 indent_up();
1060
Mark Slee12f66312007-01-17 19:19:21 +00001061 string argsname = php_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_args";
1062 string resultname = php_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_result";
Mark Sleef5377b32006-10-10 01:42:59 +00001063
1064 f_service_ <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001065 indent() << "$args = new " << argsname << "();" << endl <<
1066 indent() << "$args->read($input);" << endl;
1067 if (!binary_inline_) {
Mark Sleef5377b32006-10-10 01:42:59 +00001068 f_service_ <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001069 indent() << "$input->readMessageEnd();" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +00001070 }
1071
1072 t_struct* xs = tfunction->get_xceptions();
1073 const std::vector<t_field*>& xceptions = xs->get_members();
1074 vector<t_field*>::const_iterator x_iter;
1075
David Reissc51986f2009-03-24 20:01:25 +00001076 // Declare result for non oneway function
David Reiss47329252009-03-24 20:01:02 +00001077 if (!tfunction->is_oneway()) {
Mark Sleef5377b32006-10-10 01:42:59 +00001078 f_service_ <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001079 indent() << "$result = new " << resultname << "();" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +00001080 }
1081
1082 // Try block for a function with exceptions
1083 if (xceptions.size() > 0) {
1084 f_service_ <<
1085 indent() << "try {" << endl;
1086 indent_up();
1087 }
Mark Slee5151c622007-11-06 22:11:29 +00001088
Mark Sleef5377b32006-10-10 01:42:59 +00001089 // Generate the function call
1090 t_struct* arg_struct = tfunction->get_arglist();
1091 const std::vector<t_field*>& fields = arg_struct->get_members();
1092 vector<t_field*>::const_iterator f_iter;
1093
1094 f_service_ << indent();
David Reiss47329252009-03-24 20:01:02 +00001095 if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
Mark Slee5f8237d2006-10-26 04:57:03 +00001096 f_service_ << "$result->success = ";
Mark Sleef5377b32006-10-10 01:42:59 +00001097 }
1098 f_service_ <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001099 "$this->handler_->" << tfunction->get_name() << "(";
Mark Sleef5377b32006-10-10 01:42:59 +00001100 bool first = true;
1101 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1102 if (first) {
1103 first = false;
1104 } else {
1105 f_service_ << ", ";
1106 }
Mark Slee5f8237d2006-10-26 04:57:03 +00001107 f_service_ << "$args->" << (*f_iter)->get_name();
Mark Sleef5377b32006-10-10 01:42:59 +00001108 }
1109 f_service_ << ");" << endl;
1110
David Reiss47329252009-03-24 20:01:02 +00001111 if (!tfunction->is_oneway() && xceptions.size() > 0) {
Mark Sleef5377b32006-10-10 01:42:59 +00001112 indent_down();
1113 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1114 f_service_ <<
Mark Slee86c87b02007-02-06 07:11:23 +00001115 indent() << "} catch (" << php_namespace((*x_iter)->get_type()->get_program()) << (*x_iter)->get_type()->get_name() << " $" << (*x_iter)->get_name() << ") {" << endl;
David Reiss47329252009-03-24 20:01:02 +00001116 if (!tfunction->is_oneway()) {
Mark Sleef5377b32006-10-10 01:42:59 +00001117 indent_up();
1118 f_service_ <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001119 indent() << "$result->" << (*x_iter)->get_name() << " = $" << (*x_iter)->get_name() << ";" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +00001120 indent_down();
1121 f_service_ << indent();
1122 }
1123 }
1124 f_service_ << "}" << endl;
1125 }
1126
David Reissc51986f2009-03-24 20:01:25 +00001127 // Shortcut out here for oneway functions
David Reiss47329252009-03-24 20:01:02 +00001128 if (tfunction->is_oneway()) {
Mark Sleef5377b32006-10-10 01:42:59 +00001129 f_service_ <<
1130 indent() << "return;" << endl;
1131 indent_down();
Mark Slee5f8237d2006-10-26 04:57:03 +00001132 f_service_ <<
1133 indent() << "}" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +00001134 return;
1135 }
1136
1137 // Serialize the request header
1138 if (binary_inline_) {
1139 f_service_ <<
dweatherford969b2262007-10-23 00:26:44 +00001140 indent() << "$buff = pack('N', (0x80010000 | TMessageType::REPLY)); " << endl <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001141 indent() << "$buff .= pack('N', strlen('" << tfunction->get_name() << "'));" << endl <<
1142 indent() << "$buff .= '" << tfunction->get_name() << "';" << endl <<
dweatherford969b2262007-10-23 00:26:44 +00001143 indent() << "$buff .= pack('N', $seqid);" << endl <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001144 indent() << "$result->write($buff);" << endl <<
1145 indent() << "$output->write($buff);" << endl <<
1146 indent() << "$output->flush();" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +00001147 } else {
1148 f_service_ <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001149 indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', TMessageType::REPLY, $seqid);" << endl <<
1150 indent() << "$result->write($output);" << endl <<
Mark Slee9f8361f2007-02-09 02:14:43 +00001151 indent() << "$output->getTransport()->flush();" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +00001152 }
1153
1154 // Close function
1155 indent_down();
1156 f_service_ <<
1157 indent() << "}" << endl;
1158}
1159
1160/**
Mark Slee9cb7c612006-09-01 22:17:45 +00001161 * Generates helper functions for a service.
1162 *
1163 * @param tservice The service to generate a header definition for
1164 */
1165void t_php_generator::generate_service_helpers(t_service* tservice) {
1166 vector<t_function*> functions = tservice->get_functions();
1167 vector<t_function*>::iterator f_iter;
1168
1169 f_service_ <<
1170 "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
1171
1172 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1173 t_struct* ts = (*f_iter)->get_arglist();
Mark Sleef77ff062006-09-29 21:33:55 +00001174 string name = ts->get_name();
1175 ts->set_name(service_name_ + "_" + name);
Mark Slee9cb7c612006-09-01 22:17:45 +00001176 generate_php_struct_definition(f_service_, ts, false);
Mark Slee9cb7c612006-09-01 22:17:45 +00001177 generate_php_function_helpers(*f_iter);
Mark Sleef77ff062006-09-29 21:33:55 +00001178 ts->set_name(name);
Mark Slee9cb7c612006-09-01 22:17:45 +00001179 }
1180}
1181
1182/**
1183 * Generates a struct and helpers for a function.
1184 *
1185 * @param tfunction The function
1186 */
1187void t_php_generator::generate_php_function_helpers(t_function* tfunction) {
David Reiss47329252009-03-24 20:01:02 +00001188 if (!tfunction->is_oneway()) {
James Wangd3f1a2d2007-08-31 23:45:53 +00001189 t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result");
1190 t_field success(tfunction->get_returntype(), "success", 0);
1191 if (!tfunction->get_returntype()->is_void()) {
1192 result.append(&success);
1193 }
Mark Slee9cb7c612006-09-01 22:17:45 +00001194
James Wangd3f1a2d2007-08-31 23:45:53 +00001195 t_struct* xs = tfunction->get_xceptions();
1196 const vector<t_field*>& fields = xs->get_members();
1197 vector<t_field*>::const_iterator f_iter;
1198 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1199 result.append(*f_iter);
1200 }
Mark Slee9cb7c612006-09-01 22:17:45 +00001201
James Wangd3f1a2d2007-08-31 23:45:53 +00001202 generate_php_struct_definition(f_service_, &result, false);
1203 }
Mark Slee9cb7c612006-09-01 22:17:45 +00001204}
1205
1206/**
Mark Slee6e536442006-06-30 18:28:50 +00001207 * Generates a service interface definition.
1208 *
1209 * @param tservice The service to generate a header definition for
1210 */
1211void t_php_generator::generate_service_interface(t_service* tservice) {
Mark Sleef0712dc2006-10-25 19:03:57 +00001212 string extends = "";
1213 string extends_if = "";
1214 if (tservice->get_extends() != NULL) {
1215 extends = " extends " + tservice->get_extends()->get_name();
1216 extends_if = " extends " + tservice->get_extends()->get_name() + "If";
1217 }
Mark Slee6e536442006-06-30 18:28:50 +00001218 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001219 "interface " << service_name_ << "If" << extends_if << " {" << endl;
Mark Slee6e536442006-06-30 18:28:50 +00001220 indent_up();
1221 vector<t_function*> functions = tservice->get_functions();
Mark Slee5151c622007-11-06 22:11:29 +00001222 vector<t_function*>::iterator f_iter;
Mark Slee6e536442006-06-30 18:28:50 +00001223 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1224 indent(f_service_) <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001225 "public function " << function_signature(*f_iter) << ";" << endl;
Mark Slee6e536442006-06-30 18:28:50 +00001226 }
1227 indent_down();
1228 f_service_ <<
1229 "}" << endl << endl;
1230}
1231
1232/**
Mark Slee5ea94d42006-11-14 23:48:00 +00001233 * Generates a REST interface
1234 */
1235void t_php_generator::generate_service_rest(t_service* tservice) {
1236 string extends = "";
1237 string extends_if = "";
1238 if (tservice->get_extends() != NULL) {
1239 extends = " extends " + tservice->get_extends()->get_name();
1240 extends_if = " extends " + tservice->get_extends()->get_name() + "Rest";
1241 }
1242 f_service_ <<
Mark Slee6e81b3f2006-11-14 23:51:27 +00001243 "class " << service_name_ << "Rest" << extends_if << " {" << endl;
Mark Slee5ea94d42006-11-14 23:48:00 +00001244 indent_up();
Mark Slee21135c32007-02-05 21:52:08 +00001245
1246 if (extends.empty()) {
1247 f_service_ <<
1248 indent() << "protected $impl_;" << endl <<
1249 endl;
1250 }
1251
Mark Slee5ea94d42006-11-14 23:48:00 +00001252 f_service_ <<
Mark Slee5ea94d42006-11-14 23:48:00 +00001253 indent() << "public function __construct($impl) {" << endl <<
1254 indent() << " $this->impl_ = $impl;" << endl <<
1255 indent() << "}" << endl <<
1256 endl;
1257
1258 vector<t_function*> functions = tservice->get_functions();
Mark Slee5151c622007-11-06 22:11:29 +00001259 vector<t_function*>::iterator f_iter;
Mark Slee5ea94d42006-11-14 23:48:00 +00001260 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1261 indent(f_service_) <<
1262 "public function " << (*f_iter)->get_name() << "($request) {" << endl;
1263 indent_up();
1264 const vector<t_field*>& args = (*f_iter)->get_arglist()->get_members();
1265 vector<t_field*>::const_iterator a_iter;
1266 for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
David Reisse087a302007-08-23 21:43:25 +00001267 t_type* atype = get_true_type((*a_iter)->get_type());
Mark Sleeb1ad0142007-07-10 16:48:37 +00001268 string cast = type_to_cast(atype);
Mark Slee21135c32007-02-05 21:52:08 +00001269 string req = "$request['" + (*a_iter)->get_name() + "']";
Mark Slee5b743072007-11-13 04:00:29 +00001270 if (atype->is_bool()) {
1271 f_service_ <<
1272 indent() << "$" << (*a_iter)->get_name() << " = " << cast << "(!empty(" << req << ") && (" << req << " !== 'false'));" << endl;
1273 } else {
1274 f_service_ <<
1275 indent() << "$" << (*a_iter)->get_name() << " = isset(" << req << ") ? " << cast << req << " : null;" << endl;
1276 }
Mark Sleeb6200d82007-01-19 19:14:36 +00001277 if (atype->is_string() &&
1278 ((t_base_type*)atype)->is_string_list()) {
Mark Slee5151c622007-11-06 22:11:29 +00001279 f_service_ <<
Mark Slee5ea94d42006-11-14 23:48:00 +00001280 indent() << "$" << (*a_iter)->get_name() << " = explode(',', $" << (*a_iter)->get_name() << ");" << endl;
Mark Slee6c848a02007-10-08 22:31:03 +00001281 } else if (atype->is_map() || atype->is_list()) {
Mark Slee5151c622007-11-06 22:11:29 +00001282 f_service_ <<
Mark Slee165eca92007-10-04 01:19:20 +00001283 indent() << "$" << (*a_iter)->get_name() << " = json_decode($" << (*a_iter)->get_name() << ", true);" << endl;
Mark Slee165eca92007-10-04 01:19:20 +00001284 } else if (atype->is_set()) {
Mark Slee5151c622007-11-06 22:11:29 +00001285 f_service_ <<
Mark Slee6c848a02007-10-08 22:31:03 +00001286 indent() << "$" << (*a_iter)->get_name() << " = array_fill_keys(json_decode($" << (*a_iter)->get_name() << ", true), 1);" << endl;
Mark Slee65e595f2007-10-15 21:32:12 +00001287 } else if (atype->is_struct() || atype->is_xception()) {
Mark Slee5151c622007-11-06 22:11:29 +00001288 f_service_ <<
David Reiss051fbd42008-04-29 00:29:45 +00001289 indent() << "if ($" << (*a_iter)->get_name() << " !== null) {" << endl <<
1290 indent() << " $" << (*a_iter)->get_name() << " = new " << php_namespace(atype->get_program()) << atype->get_name() << "(json_decode($" << (*a_iter)->get_name() << ", true));" << endl <<
1291 indent() << "}" << endl;
Mark Slee165eca92007-10-04 01:19:20 +00001292 }
Mark Slee5ea94d42006-11-14 23:48:00 +00001293 }
1294 f_service_ <<
1295 indent() << "return $this->impl_->" << (*f_iter)->get_name() << "(" << argument_list((*f_iter)->get_arglist()) << ");" << endl;
1296 indent_down();
1297 indent(f_service_) <<
1298 "}" << endl <<
1299 endl;
1300 }
1301 indent_down();
1302 f_service_ <<
Mark Slee5151c622007-11-06 22:11:29 +00001303 "}" << endl << endl;
Mark Slee5ea94d42006-11-14 23:48:00 +00001304}
1305
Mark Slee09f69e02007-11-17 00:32:36 +00001306void t_php_generator::generate_service_client(t_service* tservice) {
1307 if (autoload_) {
1308 // Make output file
1309 ofstream autoload_out;
1310 string f_struct = program_name_+"."+(tservice->get_name())+".client.php";
David Reissbb97bef2009-09-16 16:57:05 +00001311 string f_struct_name = package_dir_+f_struct;
Mark Slee09f69e02007-11-17 00:32:36 +00001312 autoload_out.open(f_struct_name.c_str());
1313 autoload_out << "<?php" << endl;
1314 _generate_service_client(autoload_out, tservice);
1315 autoload_out << endl << "?>" << endl;
1316 autoload_out.close();
1317
1318 f_service_ <<
Mark Sleee02ab332007-11-28 04:17:49 +00001319 "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(service_name_ + "Client") << "'] = '" << program_name_ << "/" << f_struct << "';" << endl;
Mark Slee09f69e02007-11-17 00:32:36 +00001320
1321 } else {
1322 _generate_service_client(f_service_, tservice);
1323 }
1324}
1325
Mark Slee5ea94d42006-11-14 23:48:00 +00001326/**
Mark Slee6e536442006-06-30 18:28:50 +00001327 * Generates a service client definition.
1328 *
1329 * @param tservice The service to generate a server for.
1330 */
Mark Slee09f69e02007-11-17 00:32:36 +00001331void t_php_generator::_generate_service_client(ofstream& out, t_service* tservice) {
Mark Sleef0712dc2006-10-25 19:03:57 +00001332 string extends = "";
1333 string extends_client = "";
1334 if (tservice->get_extends() != NULL) {
1335 extends = tservice->get_extends()->get_name();
1336 extends_client = " extends " + extends + "Client";
Mark Slee52f643d2006-08-09 00:03:43 +00001337 }
Mark Slee6e536442006-06-30 18:28:50 +00001338
Mark Slee09f69e02007-11-17 00:32:36 +00001339 out <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001340 "class " << service_name_ << "Client" << extends_client << " implements " << service_name_ << "If {" << endl;
1341 indent_up();
1342
1343 // Private members
1344 if (extends.empty()) {
Mark Slee09f69e02007-11-17 00:32:36 +00001345 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001346 indent() << "protected $input_ = null;" << endl <<
1347 indent() << "protected $output_ = null;" << endl <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001348 endl;
Mark Slee09f69e02007-11-17 00:32:36 +00001349 out <<
Mark Sleed3bc1a52006-11-27 20:25:43 +00001350 indent() << "protected $seqid_ = 0;" << endl <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001351 endl;
1352 }
Mark Slee9cb7c612006-09-01 22:17:45 +00001353
Mark Slee6e536442006-06-30 18:28:50 +00001354 // Constructor function
Mark Slee09f69e02007-11-17 00:32:36 +00001355 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001356 indent() << "public function __construct($input, $output=null) {" << endl;
Mark Sleef0712dc2006-10-25 19:03:57 +00001357 if (!extends.empty()) {
Mark Slee09f69e02007-11-17 00:32:36 +00001358 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001359 indent() << " parent::__construct($input, $output);" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001360 } else {
Mark Slee09f69e02007-11-17 00:32:36 +00001361 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001362 indent() << " $this->input_ = $input;" << endl <<
1363 indent() << " $this->output_ = $output ? $output : $input;" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001364 }
Mark Slee09f69e02007-11-17 00:32:36 +00001365 out <<
Mark Slee5151c622007-11-06 22:11:29 +00001366 indent() << "}" << endl << endl;
Mark Slee6e536442006-06-30 18:28:50 +00001367
1368 // Generate client method implementations
1369 vector<t_function*> functions = tservice->get_functions();
Mark Slee5151c622007-11-06 22:11:29 +00001370 vector<t_function*>::const_iterator f_iter;
Mark Slee6e536442006-06-30 18:28:50 +00001371 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
Mark Slee9cb7c612006-09-01 22:17:45 +00001372 t_struct* arg_struct = (*f_iter)->get_arglist();
1373 const vector<t_field*>& fields = arg_struct->get_members();
1374 vector<t_field*>::const_iterator fld_iter;
Mark Slee6e536442006-06-30 18:28:50 +00001375 string funname = (*f_iter)->get_name();
1376
1377 // Open function
Mark Slee09f69e02007-11-17 00:32:36 +00001378 indent(out) <<
Mark Slee6e536442006-06-30 18:28:50 +00001379 "public function " << function_signature(*f_iter) << endl;
Mark Slee09f69e02007-11-17 00:32:36 +00001380 scope_up(out);
1381 indent(out) <<
Mark Slee9cb7c612006-09-01 22:17:45 +00001382 "$this->send_" << funname << "(";
Mark Slee6e536442006-06-30 18:28:50 +00001383
Mark Slee9cb7c612006-09-01 22:17:45 +00001384 bool first = true;
1385 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1386 if (first) {
1387 first = false;
1388 } else {
Mark Slee09f69e02007-11-17 00:32:36 +00001389 out << ", ";
Mark Slee9cb7c612006-09-01 22:17:45 +00001390 }
Mark Slee09f69e02007-11-17 00:32:36 +00001391 out << "$" << (*fld_iter)->get_name();
Mark Slee9cb7c612006-09-01 22:17:45 +00001392 }
Mark Slee09f69e02007-11-17 00:32:36 +00001393 out << ");" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001394
David Reiss47329252009-03-24 20:01:02 +00001395 if (!(*f_iter)->is_oneway()) {
Mark Slee09f69e02007-11-17 00:32:36 +00001396 out << indent();
Mark Slee9cb7c612006-09-01 22:17:45 +00001397 if (!(*f_iter)->get_returntype()->is_void()) {
Mark Slee09f69e02007-11-17 00:32:36 +00001398 out << "return ";
Mark Slee9cb7c612006-09-01 22:17:45 +00001399 }
Mark Slee09f69e02007-11-17 00:32:36 +00001400 out <<
Mark Slee9cb7c612006-09-01 22:17:45 +00001401 "$this->recv_" << funname << "();" << endl;
1402 }
Mark Slee09f69e02007-11-17 00:32:36 +00001403 scope_down(out);
1404 out << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001405
Mark Slee09f69e02007-11-17 00:32:36 +00001406 indent(out) <<
Mark Slee9cb7c612006-09-01 22:17:45 +00001407 "public function send_" << function_signature(*f_iter) << endl;
Mark Slee09f69e02007-11-17 00:32:36 +00001408 scope_up(out);
Mark Slee6e536442006-06-30 18:28:50 +00001409
Mark Slee12f66312007-01-17 19:19:21 +00001410 std::string argsname = php_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_args";
Mark Slee6e536442006-06-30 18:28:50 +00001411
dweatherfordcf997a42008-03-04 01:08:23 +00001412 out <<
1413 indent() << "$args = new " << argsname << "();" << endl;
1414
1415 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1416 out <<
1417 indent() << "$args->" << (*fld_iter)->get_name() << " = $" << (*fld_iter)->get_name() << ";" << endl;
1418 }
1419
1420 out <<
1421 indent() << "$bin_accel = ($this->output_ instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_write_binary');" << endl;
1422
1423 out <<
1424 indent() << "if ($bin_accel)" << endl;
1425 scope_up(out);
1426
1427 out <<
1428 indent() << "thrift_protocol_write_binary($this->output_, '" << (*f_iter)->get_name() << "', TMessageType::CALL, $args, $this->seqid_, $this->output_->isStrictWrite());" << endl;
1429
1430 scope_down(out);
1431 out <<
1432 indent() << "else" << endl;
1433 scope_up(out);
1434
Mark Slee9cb7c612006-09-01 22:17:45 +00001435 // Serialize the request header
1436 if (binary_inline_) {
Mark Slee09f69e02007-11-17 00:32:36 +00001437 out <<
dweatherford969b2262007-10-23 00:26:44 +00001438 indent() << "$buff = pack('N', (0x80010000 | TMessageType::CALL));" << endl <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001439 indent() << "$buff .= pack('N', strlen('" << funname << "'));" << endl <<
1440 indent() << "$buff .= '" << funname << "';" << endl <<
dweatherford969b2262007-10-23 00:26:44 +00001441 indent() << "$buff .= pack('N', $this->seqid_);" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +00001442 } else {
Mark Slee09f69e02007-11-17 00:32:36 +00001443 out <<
Mark Sleed3bc1a52006-11-27 20:25:43 +00001444 indent() << "$this->output_->writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType::CALL, $this->seqid_);" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +00001445 }
Mark Slee5151c622007-11-06 22:11:29 +00001446
Mark Slee9cb7c612006-09-01 22:17:45 +00001447 // Write to the stream
Mark Slee5151c622007-11-06 22:11:29 +00001448 if (binary_inline_) {
Mark Slee09f69e02007-11-17 00:32:36 +00001449 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001450 indent() << "$args->write($buff);" << endl <<
1451 indent() << "$this->output_->write($buff);" << endl <<
1452 indent() << "$this->output_->flush();" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +00001453 } else {
Mark Slee09f69e02007-11-17 00:32:36 +00001454 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001455 indent() << "$args->write($this->output_);" << endl <<
1456 indent() << "$this->output_->writeMessageEnd();" << endl <<
Mark Slee9f8361f2007-02-09 02:14:43 +00001457 indent() << "$this->output_->getTransport()->flush();" << endl;
Mark Slee5151c622007-11-06 22:11:29 +00001458 }
1459
Mark Slee09f69e02007-11-17 00:32:36 +00001460 scope_down(out);
Mark Slee5151c622007-11-06 22:11:29 +00001461
dweatherfordcf997a42008-03-04 01:08:23 +00001462 scope_down(out);
1463
Mark Slee6e536442006-06-30 18:28:50 +00001464
David Reiss47329252009-03-24 20:01:02 +00001465 if (!(*f_iter)->is_oneway()) {
Mark Slee12f66312007-01-17 19:19:21 +00001466 std::string resultname = php_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result";
Mark Sleef0712dc2006-10-25 19:03:57 +00001467 t_struct noargs(program_);
Mark Slee5151c622007-11-06 22:11:29 +00001468
Mark Slee9cb7c612006-09-01 22:17:45 +00001469 t_function recv_function((*f_iter)->get_returntype(),
1470 string("recv_") + (*f_iter)->get_name(),
1471 &noargs);
1472 // Open function
Mark Slee09f69e02007-11-17 00:32:36 +00001473 out <<
Mark Slee9cb7c612006-09-01 22:17:45 +00001474 endl <<
1475 indent() << "public function " << function_signature(&recv_function) << endl;
Mark Slee09f69e02007-11-17 00:32:36 +00001476 scope_up(out);
Mark Slee6e536442006-06-30 18:28:50 +00001477
Mark Slee09f69e02007-11-17 00:32:36 +00001478 out <<
dweatherfordcf997a42008-03-04 01:08:23 +00001479 indent() << "$bin_accel = ($this->input_ instanceof TProtocol::$TBINARYPROTOCOLACCELERATED)"
1480 << " && function_exists('thrift_protocol_read_binary');" << endl;
1481
1482 out <<
1483 indent() << "if ($bin_accel) $result = thrift_protocol_read_binary($this->input_, '" << resultname << "', $this->input_->isStrictRead());" << endl;
1484 out <<
1485 indent() << "else" << endl;
1486 scope_up(out);
1487
1488 out <<
Mark Slee9cb7c612006-09-01 22:17:45 +00001489 indent() << "$rseqid = 0;" << endl <<
1490 indent() << "$fname = null;" << endl <<
1491 indent() << "$mtype = 0;" << endl <<
1492 endl;
1493
1494 if (binary_inline_) {
Mark Sleef0712dc2006-10-25 19:03:57 +00001495 t_field ffname(g_type_string, "fname");
Mark Sleef0712dc2006-10-25 19:03:57 +00001496 t_field fseqid(g_type_i32, "rseqid");
Mark Slee09f69e02007-11-17 00:32:36 +00001497 out <<
dweatherford969b2262007-10-23 00:26:44 +00001498 indent() << "$ver = unpack('N', $this->input_->readAll(4));" << endl <<
1499 indent() << "$ver = $ver[1];" << endl <<
1500 indent() << "$mtype = $ver & 0xff;" << endl <<
1501 indent() << "$ver = $ver & 0xffff0000;" << endl <<
1502 indent() << "if ($ver != 0x80010000) throw new TProtocolException('Bad version identifier: '.$ver, TProtocolException::BAD_VERSION);" << endl;
Mark Slee09f69e02007-11-17 00:32:36 +00001503 generate_deserialize_field(out, &ffname, "", true);
1504 generate_deserialize_field(out, &fseqid, "", true);
Mark Slee9cb7c612006-09-01 22:17:45 +00001505 } else {
Mark Slee09f69e02007-11-17 00:32:36 +00001506 out <<
Mark Slee7a498882007-02-27 22:11:39 +00001507 indent() << "$this->input_->readMessageBegin($fname, $mtype, $rseqid);" << endl <<
1508 indent() << "if ($mtype == TMessageType::EXCEPTION) {" << endl <<
1509 indent() << " $x = new TApplicationException();" << endl <<
Martin Kraemera7d6c3c2007-03-16 02:03:32 +00001510 indent() << " $x->read($this->input_);" << endl <<
1511 indent() << " $this->input_->readMessageEnd();" << endl <<
Mark Slee7a498882007-02-27 22:11:39 +00001512 indent() << " throw $x;" << endl <<
1513 indent() << "}" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +00001514 }
1515
Mark Slee09f69e02007-11-17 00:32:36 +00001516 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001517 indent() << "$result = new " << resultname << "();" << endl <<
1518 indent() << "$result->read($this->input_);" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +00001519
1520 if (!binary_inline_) {
Mark Slee09f69e02007-11-17 00:32:36 +00001521 out <<
dweatherford6b53bbb2008-03-11 02:42:45 +00001522 indent() << "$this->input_->readMessageEnd();" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +00001523 }
1524
dweatherford6b53bbb2008-03-11 02:42:45 +00001525 scope_down(out);
1526
Mark Slee5f8237d2006-10-26 04:57:03 +00001527 // Careful, only return result if not a void function
Mark Slee9cb7c612006-09-01 22:17:45 +00001528 if (!(*f_iter)->get_returntype()->is_void()) {
Mark Slee09f69e02007-11-17 00:32:36 +00001529 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001530 indent() << "if ($result->success !== null) {" << endl <<
1531 indent() << " return $result->success;" << endl <<
Mark Slee9cb7c612006-09-01 22:17:45 +00001532 indent() << "}" << endl;
1533 }
1534
1535 t_struct* xs = (*f_iter)->get_xceptions();
1536 const std::vector<t_field*>& xceptions = xs->get_members();
1537 vector<t_field*>::const_iterator x_iter;
1538 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
Mark Slee09f69e02007-11-17 00:32:36 +00001539 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001540 indent() << "if ($result->" << (*x_iter)->get_name() << " !== null) {" << endl <<
1541 indent() << " throw $result->" << (*x_iter)->get_name() << ";" << endl <<
Mark Slee9cb7c612006-09-01 22:17:45 +00001542 indent() << "}" << endl;
1543 }
1544
1545 // Careful, only return _result if not a void function
1546 if ((*f_iter)->get_returntype()->is_void()) {
Mark Slee09f69e02007-11-17 00:32:36 +00001547 indent(out) <<
Mark Slee9cb7c612006-09-01 22:17:45 +00001548 "return;" << endl;
1549 } else {
Mark Slee09f69e02007-11-17 00:32:36 +00001550 out <<
Mark Sleec98d0502006-09-06 02:42:25 +00001551 indent() << "throw new Exception(\"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
Mark Slee5151c622007-11-06 22:11:29 +00001552 }
Mark Slee6e536442006-06-30 18:28:50 +00001553
1554 // Close function
Mark Slee09f69e02007-11-17 00:32:36 +00001555 scope_down(out);
1556 out << endl;
Mark Slee794993d2006-09-20 01:56:10 +00001557
Mark Slee5151c622007-11-06 22:11:29 +00001558 }
Mark Slee6e536442006-06-30 18:28:50 +00001559 }
1560
1561 indent_down();
Mark Slee09f69e02007-11-17 00:32:36 +00001562 out <<
Mark Slee9cb7c612006-09-01 22:17:45 +00001563 "}" << endl << endl;
Mark Slee6e536442006-06-30 18:28:50 +00001564}
1565
1566/**
1567 * Deserializes a field of any type.
1568 */
Mark Slee9cb7c612006-09-01 22:17:45 +00001569void t_php_generator::generate_deserialize_field(ofstream &out,
1570 t_field* tfield,
1571 string prefix,
1572 bool inclass) {
David Reisse087a302007-08-23 21:43:25 +00001573 t_type* type = get_true_type(tfield->get_type());
Mark Slee6e536442006-06-30 18:28:50 +00001574
1575 if (type->is_void()) {
1576 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1577 prefix + tfield->get_name();
1578 }
1579
1580 string name = prefix + tfield->get_name();
1581
Mark Slee9cb7c612006-09-01 22:17:45 +00001582 if (type->is_struct() || type->is_xception()) {
1583 generate_deserialize_struct(out,
Mark Slee216e7d62006-11-21 00:44:23 +00001584 (t_struct*)type,
Mark Slee9cb7c612006-09-01 22:17:45 +00001585 name);
Mark Slee6e536442006-06-30 18:28:50 +00001586 } else {
dweatherford5afc0aa2007-10-31 06:03:54 +00001587
1588 if (type->is_container()) {
1589 generate_deserialize_container(out, type, name);
1590 } else if (type->is_base_type() || type->is_enum()) {
1591
dweatherford5afc0aa2007-10-31 06:03:54 +00001592 if (binary_inline_) {
1593 std::string itrans = (inclass ? "$this->input_" : "$input");
1594
1595 if (type->is_base_type()) {
1596 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1597 switch (tbase) {
1598 case t_base_type::TYPE_VOID:
1599 throw "compiler error: cannot serialize void field in a struct: " +
1600 name;
1601 break;
1602 case t_base_type::TYPE_STRING:
1603 out <<
1604 indent() << "$len = unpack('N', " << itrans << "->readAll(4));" << endl <<
1605 indent() << "$len = $len[1];" << endl <<
1606 indent() << "if ($len > 0x7fffffff) {" << endl <<
1607 indent() << " $len = 0 - (($len - 1) ^ 0xffffffff);" << endl <<
1608 indent() << "}" << endl <<
1609 indent() << "$" << name << " = " << itrans << "->readAll($len);" << endl;
1610 break;
1611 case t_base_type::TYPE_BOOL:
1612 out <<
1613 indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl <<
1614 indent() << "$" << name << " = (bool)$" << name << "[1];" << endl;
1615 break;
1616 case t_base_type::TYPE_BYTE:
1617 out <<
1618 indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl <<
1619 indent() << "$" << name << " = $" << name << "[1];" << endl;
1620 break;
1621 case t_base_type::TYPE_I16:
1622 out <<
1623 indent() << "$val = unpack('n', " << itrans << "->readAll(2));" << endl <<
1624 indent() << "$val = $val[1];" << endl <<
1625 indent() << "if ($val > 0x7fff) {" << endl <<
1626 indent() << " $val = 0 - (($val - 1) ^ 0xffff);" << endl <<
1627 indent() << "}" << endl <<
1628 indent() << "$" << name << " = $val;" << endl;
1629 break;
1630 case t_base_type::TYPE_I32:
1631 out <<
1632 indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl <<
1633 indent() << "$val = $val[1];" << endl <<
1634 indent() << "if ($val > 0x7fffffff) {" << endl <<
1635 indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl <<
1636 indent() << "}" << endl <<
1637 indent() << "$" << name << " = $val;" << endl;
1638 break;
1639 case t_base_type::TYPE_I64:
1640 out <<
1641 indent() << "$arr = unpack('N2', " << itrans << "->readAll(8));" << endl <<
1642 indent() << "if ($arr[1] & 0x80000000) {" << endl <<
1643 indent() << " $arr[1] = $arr[1] ^ 0xFFFFFFFF;" << endl <<
1644 indent() << " $arr[2] = $arr[2] ^ 0xFFFFFFFF;" << endl <<
1645 indent() << " $" << name << " = 0 - $arr[1]*4294967296 - $arr[2] - 1;" << endl <<
1646 indent() << "} else {" << endl <<
1647 indent() << " $" << name << " = $arr[1]*4294967296 + $arr[2];" << endl <<
1648 indent() << "}" << endl;
1649 break;
1650 case t_base_type::TYPE_DOUBLE:
1651 out <<
1652 indent() << "$arr = unpack('d', strrev(" << itrans << "->readAll(8)));" << endl <<
1653 indent() << "$" << name << " = $arr[1];" << endl;
1654 break;
1655 default:
1656 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase) + tfield->get_name();
1657 }
1658 } else if (type->is_enum()) {
1659 out <<
1660 indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl <<
1661 indent() << "$val = $val[1];" << endl <<
1662 indent() << "if ($val > 0x7fffffff) {" << endl <<
1663 indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl <<
1664 indent() << "}" << endl <<
1665 indent() << "$" << name << " = $val;" << endl;
1666 }
1667 } else {
1668
1669 indent(out) <<
1670 "$xfer += $input->";
Mark Slee5151c622007-11-06 22:11:29 +00001671
dweatherford5afc0aa2007-10-31 06:03:54 +00001672 if (type->is_base_type()) {
1673 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1674 switch (tbase) {
1675 case t_base_type::TYPE_VOID:
1676 throw "compiler error: cannot serialize void field in a struct: " +
1677 name;
1678 break;
Mark Slee5151c622007-11-06 22:11:29 +00001679 case t_base_type::TYPE_STRING:
dweatherford5afc0aa2007-10-31 06:03:54 +00001680 out << "readString($" << name << ");";
1681 break;
1682 case t_base_type::TYPE_BOOL:
1683 out << "readBool($" << name << ");";
1684 break;
1685 case t_base_type::TYPE_BYTE:
1686 out << "readByte($" << name << ");";
1687 break;
1688 case t_base_type::TYPE_I16:
1689 out << "readI16($" << name << ");";
1690 break;
1691 case t_base_type::TYPE_I32:
1692 out << "readI32($" << name << ");";
1693 break;
1694 case t_base_type::TYPE_I64:
1695 out << "readI64($" << name << ");";
1696 break;
1697 case t_base_type::TYPE_DOUBLE:
1698 out << "readDouble($" << name << ");";
1699 break;
1700 default:
1701 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
1702 }
1703 } else if (type->is_enum()) {
1704 out << "readI32($" << name << ");";
1705 }
1706 out << endl;
1707 }
dweatherford5afc0aa2007-10-31 06:03:54 +00001708 } else {
1709 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
1710 tfield->get_name().c_str(), type->get_name().c_str());
1711 }
1712 }
Mark Slee6e536442006-06-30 18:28:50 +00001713}
1714
1715/**
1716 * Generates an unserializer for a variable. This makes two key assumptions,
1717 * first that there is a const char* variable named data that points to the
1718 * buffer for deserialization, and that there is a variable protocol which
1719 * is a reference to a TProtocol serialization object.
1720 */
Mark Slee9cb7c612006-09-01 22:17:45 +00001721void t_php_generator::generate_deserialize_struct(ofstream &out,
1722 t_struct* tstruct,
Mark Slee6e536442006-06-30 18:28:50 +00001723 string prefix) {
Mark Slee9cb7c612006-09-01 22:17:45 +00001724 out <<
Mark Sleee888b372007-01-12 01:06:24 +00001725 indent() << "$" << prefix << " = new " << php_namespace(tstruct->get_program()) << tstruct->get_name() << "();" << endl <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001726 indent() << "$xfer += $" << prefix << "->read($input);" << endl;
Mark Slee6e536442006-06-30 18:28:50 +00001727}
1728
Mark Slee9cb7c612006-09-01 22:17:45 +00001729void t_php_generator::generate_deserialize_container(ofstream &out,
1730 t_type* ttype,
Mark Slee6e536442006-06-30 18:28:50 +00001731 string prefix) {
Mark Slee6e536442006-06-30 18:28:50 +00001732 string size = tmp("_size");
1733 string ktype = tmp("_ktype");
1734 string vtype = tmp("_vtype");
1735 string etype = tmp("_etype");
Mark Slee5151c622007-11-06 22:11:29 +00001736
Mark Sleef0712dc2006-10-25 19:03:57 +00001737 t_field fsize(g_type_i32, size);
1738 t_field fktype(g_type_byte, ktype);
1739 t_field fvtype(g_type_byte, vtype);
1740 t_field fetype(g_type_byte, etype);
Mark Slee52f643d2006-08-09 00:03:43 +00001741
Mark Sleec98d0502006-09-06 02:42:25 +00001742 out <<
1743 indent() << "$" << prefix << " = array();" << endl <<
1744 indent() << "$" << size << " = 0;" << endl;
Mark Slee5151c622007-11-06 22:11:29 +00001745
Mark Slee6e536442006-06-30 18:28:50 +00001746 // Declare variables, read header
1747 if (ttype->is_map()) {
Mark Slee9cb7c612006-09-01 22:17:45 +00001748 out <<
Mark Slee6e536442006-06-30 18:28:50 +00001749 indent() << "$" << ktype << " = 0;" << endl <<
Mark Slee52f643d2006-08-09 00:03:43 +00001750 indent() << "$" << vtype << " = 0;" << endl;
1751 if (binary_inline_) {
Mark Slee9cb7c612006-09-01 22:17:45 +00001752 generate_deserialize_field(out, &fktype);
1753 generate_deserialize_field(out, &fvtype);
1754 generate_deserialize_field(out, &fsize);
Mark Slee52f643d2006-08-09 00:03:43 +00001755 } else {
Mark Slee9cb7c612006-09-01 22:17:45 +00001756 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001757 indent() << "$xfer += $input->readMapBegin(" <<
Mark Slee52f643d2006-08-09 00:03:43 +00001758 "$" << ktype << ", $" << vtype << ", $" << size << ");" << endl;
1759 }
Mark Slee6e536442006-06-30 18:28:50 +00001760 } else if (ttype->is_set()) {
Mark Slee52f643d2006-08-09 00:03:43 +00001761 if (binary_inline_) {
Mark Slee9cb7c612006-09-01 22:17:45 +00001762 generate_deserialize_field(out, &fetype);
1763 generate_deserialize_field(out, &fsize);
Mark Slee52f643d2006-08-09 00:03:43 +00001764 } else {
Mark Slee9cb7c612006-09-01 22:17:45 +00001765 out <<
Mark Slee52f643d2006-08-09 00:03:43 +00001766 indent() << "$" << etype << " = 0;" << endl <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001767 indent() << "$xfer += $input->readSetBegin(" <<
Mark Slee52f643d2006-08-09 00:03:43 +00001768 "$" << etype << ", $" << size << ");" << endl;
1769 }
Mark Slee6e536442006-06-30 18:28:50 +00001770 } else if (ttype->is_list()) {
Mark Slee52f643d2006-08-09 00:03:43 +00001771 if (binary_inline_) {
Mark Slee9cb7c612006-09-01 22:17:45 +00001772 generate_deserialize_field(out, &fetype);
1773 generate_deserialize_field(out, &fsize);
Mark Slee52f643d2006-08-09 00:03:43 +00001774 } else {
Mark Slee9cb7c612006-09-01 22:17:45 +00001775 out <<
Mark Slee52f643d2006-08-09 00:03:43 +00001776 indent() << "$" << etype << " = 0;" << endl <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001777 indent() << "$xfer += $input->readListBegin(" <<
Mark Slee52f643d2006-08-09 00:03:43 +00001778 "$" << etype << ", $" << size << ");" << endl;
1779 }
Mark Slee6e536442006-06-30 18:28:50 +00001780 }
1781
1782 // For loop iterates over elements
1783 string i = tmp("_i");
Mark Slee9cb7c612006-09-01 22:17:45 +00001784 indent(out) <<
Mark Slee6e536442006-06-30 18:28:50 +00001785 "for ($" <<
1786 i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" << endl;
Mark Slee5151c622007-11-06 22:11:29 +00001787
Mark Slee9cb7c612006-09-01 22:17:45 +00001788 scope_up(out);
Mark Slee5151c622007-11-06 22:11:29 +00001789
Mark Slee6e536442006-06-30 18:28:50 +00001790 if (ttype->is_map()) {
Mark Slee9cb7c612006-09-01 22:17:45 +00001791 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
Mark Slee6e536442006-06-30 18:28:50 +00001792 } else if (ttype->is_set()) {
Mark Slee9cb7c612006-09-01 22:17:45 +00001793 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
Mark Slee6e536442006-06-30 18:28:50 +00001794 } else if (ttype->is_list()) {
Mark Slee9cb7c612006-09-01 22:17:45 +00001795 generate_deserialize_list_element(out, (t_list*)ttype, prefix);
Mark Slee6e536442006-06-30 18:28:50 +00001796 }
Mark Slee5151c622007-11-06 22:11:29 +00001797
Mark Slee9cb7c612006-09-01 22:17:45 +00001798 scope_down(out);
Mark Slee6e536442006-06-30 18:28:50 +00001799
Mark Slee52f643d2006-08-09 00:03:43 +00001800 if (!binary_inline_) {
1801 // Read container end
1802 if (ttype->is_map()) {
Mark Slee5f8237d2006-10-26 04:57:03 +00001803 indent(out) << "$xfer += $input->readMapEnd();" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001804 } else if (ttype->is_set()) {
Mark Slee5f8237d2006-10-26 04:57:03 +00001805 indent(out) << "$xfer += $input->readSetEnd();" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001806 } else if (ttype->is_list()) {
Mark Slee5f8237d2006-10-26 04:57:03 +00001807 indent(out) << "$xfer += $input->readListEnd();" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001808 }
Mark Slee6e536442006-06-30 18:28:50 +00001809 }
Mark Slee6e536442006-06-30 18:28:50 +00001810}
1811
1812
1813/**
1814 * Generates code to deserialize a map
1815 */
Mark Slee9cb7c612006-09-01 22:17:45 +00001816void t_php_generator::generate_deserialize_map_element(ofstream &out,
1817 t_map* tmap,
Mark Slee6e536442006-06-30 18:28:50 +00001818 string prefix) {
Mark Slee5f8237d2006-10-26 04:57:03 +00001819 string key = tmp("key");
1820 string val = tmp("val");
Mark Slee6e536442006-06-30 18:28:50 +00001821 t_field fkey(tmap->get_key_type(), key);
1822 t_field fval(tmap->get_val_type(), val);
1823
Mark Slee9cb7c612006-09-01 22:17:45 +00001824 indent(out) <<
Mark Slee6e536442006-06-30 18:28:50 +00001825 declare_field(&fkey, true, true) << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +00001826 indent(out) <<
Mark Slee6e536442006-06-30 18:28:50 +00001827 declare_field(&fval, true, true) << endl;
1828
Mark Slee9cb7c612006-09-01 22:17:45 +00001829 generate_deserialize_field(out, &fkey);
1830 generate_deserialize_field(out, &fval);
Mark Slee6e536442006-06-30 18:28:50 +00001831
Mark Slee9cb7c612006-09-01 22:17:45 +00001832 indent(out) <<
Mark Slee6e536442006-06-30 18:28:50 +00001833 "$" << prefix << "[$" << key << "] = $" << val << ";" << endl;
1834}
1835
Mark Slee9cb7c612006-09-01 22:17:45 +00001836void t_php_generator::generate_deserialize_set_element(ofstream &out,
1837 t_set* tset,
Mark Slee6e536442006-06-30 18:28:50 +00001838 string prefix) {
Mark Slee5f8237d2006-10-26 04:57:03 +00001839 string elem = tmp("elem");
Mark Slee6e536442006-06-30 18:28:50 +00001840 t_field felem(tset->get_elem_type(), elem);
1841
Mark Slee9cb7c612006-09-01 22:17:45 +00001842 indent(out) <<
Mark Slee6e536442006-06-30 18:28:50 +00001843 "$" << elem << " = null;" << endl;
1844
Mark Slee9cb7c612006-09-01 22:17:45 +00001845 generate_deserialize_field(out, &felem);
Mark Slee6e536442006-06-30 18:28:50 +00001846
Mark Slee9cb7c612006-09-01 22:17:45 +00001847 indent(out) <<
Mark Slee600cdb32006-11-29 22:06:42 +00001848 "$" << prefix << "[$" << elem << "] = true;" << endl;
Mark Slee6e536442006-06-30 18:28:50 +00001849}
1850
Mark Slee9cb7c612006-09-01 22:17:45 +00001851void t_php_generator::generate_deserialize_list_element(ofstream &out,
1852 t_list* tlist,
Mark Slee6e536442006-06-30 18:28:50 +00001853 string prefix) {
Mark Slee5f8237d2006-10-26 04:57:03 +00001854 string elem = tmp("elem");
Mark Slee6e536442006-06-30 18:28:50 +00001855 t_field felem(tlist->get_elem_type(), elem);
1856
Mark Slee9cb7c612006-09-01 22:17:45 +00001857 indent(out) <<
Mark Slee6e536442006-06-30 18:28:50 +00001858 "$" << elem << " = null;" << endl;
1859
Mark Slee9cb7c612006-09-01 22:17:45 +00001860 generate_deserialize_field(out, &felem);
Mark Slee6e536442006-06-30 18:28:50 +00001861
Mark Slee9cb7c612006-09-01 22:17:45 +00001862 indent(out) <<
Mark Slee6e536442006-06-30 18:28:50 +00001863 "$" << prefix << " []= $" << elem << ";" << endl;
1864}
1865
1866
1867/**
1868 * Serializes a field of any type.
1869 *
1870 * @param tfield The field to serialize
1871 * @param prefix Name to prepend to field name
1872 */
Mark Slee9cb7c612006-09-01 22:17:45 +00001873void t_php_generator::generate_serialize_field(ofstream &out,
1874 t_field* tfield,
Mark Slee6e536442006-06-30 18:28:50 +00001875 string prefix) {
David Reisse087a302007-08-23 21:43:25 +00001876 t_type* type = get_true_type(tfield->get_type());
Mark Slee6e536442006-06-30 18:28:50 +00001877
1878 // Do nothing for void types
1879 if (type->is_void()) {
1880 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
1881 prefix + tfield->get_name();
1882 }
Mark Slee5151c622007-11-06 22:11:29 +00001883
Mark Slee9cb7c612006-09-01 22:17:45 +00001884 if (type->is_struct() || type->is_xception()) {
1885 generate_serialize_struct(out,
Mark Slee216e7d62006-11-21 00:44:23 +00001886 (t_struct*)type,
Mark Slee9cb7c612006-09-01 22:17:45 +00001887 prefix + tfield->get_name());
Mark Slee6e536442006-06-30 18:28:50 +00001888 } else if (type->is_container()) {
Mark Slee9cb7c612006-09-01 22:17:45 +00001889 generate_serialize_container(out,
Mark Slee216e7d62006-11-21 00:44:23 +00001890 type,
Mark Slee6e536442006-06-30 18:28:50 +00001891 prefix + tfield->get_name());
1892 } else if (type->is_base_type() || type->is_enum()) {
1893
1894 string name = prefix + tfield->get_name();
Mark Slee52f643d2006-08-09 00:03:43 +00001895
1896 if (binary_inline_) {
1897 if (type->is_base_type()) {
1898 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1899 switch (tbase) {
1900 case t_base_type::TYPE_VOID:
1901 throw
1902 "compiler error: cannot serialize void field in a struct: " + name;
1903 break;
1904 case t_base_type::TYPE_STRING:
Mark Slee9cb7c612006-09-01 22:17:45 +00001905 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001906 indent() << "$output .= pack('N', strlen($" << name << "));" << endl <<
1907 indent() << "$output .= $" << name << ";" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001908 break;
Mark Slee78f58e22006-09-02 04:17:07 +00001909 case t_base_type::TYPE_BOOL:
1910 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001911 indent() << "$output .= pack('c', $" << name << " ? 1 : 0);" << endl;
Mark Slee78f58e22006-09-02 04:17:07 +00001912 break;
Mark Slee52f643d2006-08-09 00:03:43 +00001913 case t_base_type::TYPE_BYTE:
Mark Slee9cb7c612006-09-01 22:17:45 +00001914 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001915 indent() << "$output .= pack('c', $" << name << ");" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001916 break;
Mark Slee9cb7c612006-09-01 22:17:45 +00001917 case t_base_type::TYPE_I16:
1918 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001919 indent() << "$output .= pack('n', $" << name << ");" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001920 break;
Mark Slee9cb7c612006-09-01 22:17:45 +00001921 case t_base_type::TYPE_I32:
1922 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001923 indent() << "$output .= pack('N', $" << name << ");" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001924 break;
1925 case t_base_type::TYPE_I64:
Mark Slee5151c622007-11-06 22:11:29 +00001926 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001927 indent() << "$output .= pack('N2', $" << name << " >> 32, $" << name << " & 0xFFFFFFFF);" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00001928 break;
Mark Sleec98d0502006-09-06 02:42:25 +00001929 case t_base_type::TYPE_DOUBLE:
Mark Slee5151c622007-11-06 22:11:29 +00001930 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001931 indent() << "$output .= strrev(pack('d', $" << name << "));" << endl;
Mark Sleec98d0502006-09-06 02:42:25 +00001932 break;
Mark Slee52f643d2006-08-09 00:03:43 +00001933 default:
David Reissdd7796f2007-08-28 21:09:06 +00001934 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
Mark Slee52f643d2006-08-09 00:03:43 +00001935 }
1936 } else if (type->is_enum()) {
Mark Slee9cb7c612006-09-01 22:17:45 +00001937 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001938 indent() << "$output .= pack('N', $" << name << ");" << endl;
Mark Slee6e536442006-06-30 18:28:50 +00001939 }
Mark Slee52f643d2006-08-09 00:03:43 +00001940 } else {
1941
Mark Slee9cb7c612006-09-01 22:17:45 +00001942 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +00001943 "$xfer += $output->";
Mark Slee5151c622007-11-06 22:11:29 +00001944
Mark Slee52f643d2006-08-09 00:03:43 +00001945 if (type->is_base_type()) {
1946 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1947 switch (tbase) {
1948 case t_base_type::TYPE_VOID:
1949 throw
1950 "compiler error: cannot serialize void field in a struct: " + name;
1951 break;
1952 case t_base_type::TYPE_STRING:
Mark Slee5f8237d2006-10-26 04:57:03 +00001953 out << "writeString($" << name << ");";
Mark Slee52f643d2006-08-09 00:03:43 +00001954 break;
Mark Slee78f58e22006-09-02 04:17:07 +00001955 case t_base_type::TYPE_BOOL:
Mark Slee5f8237d2006-10-26 04:57:03 +00001956 out << "writeBool($" << name << ");";
Mark Slee78f58e22006-09-02 04:17:07 +00001957 break;
Mark Slee52f643d2006-08-09 00:03:43 +00001958 case t_base_type::TYPE_BYTE:
Mark Slee5f8237d2006-10-26 04:57:03 +00001959 out << "writeByte($" << name << ");";
Mark Slee9cb7c612006-09-01 22:17:45 +00001960 break;
1961 case t_base_type::TYPE_I16:
Mark Slee5f8237d2006-10-26 04:57:03 +00001962 out << "writeI16($" << name << ");";
Mark Slee52f643d2006-08-09 00:03:43 +00001963 break;
1964 case t_base_type::TYPE_I32:
Mark Slee5f8237d2006-10-26 04:57:03 +00001965 out << "writeI32($" << name << ");";
Mark Slee52f643d2006-08-09 00:03:43 +00001966 break;
1967 case t_base_type::TYPE_I64:
Mark Slee5f8237d2006-10-26 04:57:03 +00001968 out << "writeI64($" << name << ");";
Mark Slee52f643d2006-08-09 00:03:43 +00001969 break;
Mark Sleec98d0502006-09-06 02:42:25 +00001970 case t_base_type::TYPE_DOUBLE:
Mark Slee5f8237d2006-10-26 04:57:03 +00001971 out << "writeDouble($" << name << ");";
Mark Sleec98d0502006-09-06 02:42:25 +00001972 break;
Mark Slee52f643d2006-08-09 00:03:43 +00001973 default:
David Reissdd7796f2007-08-28 21:09:06 +00001974 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
Mark Slee52f643d2006-08-09 00:03:43 +00001975 }
1976 } else if (type->is_enum()) {
Mark Slee5f8237d2006-10-26 04:57:03 +00001977 out << "writeI32($" << name << ");";
Mark Slee52f643d2006-08-09 00:03:43 +00001978 }
Mark Slee9cb7c612006-09-01 22:17:45 +00001979 out << endl;
Mark Slee6e536442006-06-30 18:28:50 +00001980 }
Mark Slee6e536442006-06-30 18:28:50 +00001981 } else {
1982 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
1983 prefix.c_str(),
1984 tfield->get_name().c_str(),
Mark Sleef5377b32006-10-10 01:42:59 +00001985 type->get_name().c_str());
Mark Slee6e536442006-06-30 18:28:50 +00001986 }
1987}
1988
1989/**
1990 * Serializes all the members of a struct.
1991 *
1992 * @param tstruct The struct to serialize
1993 * @param prefix String prefix to attach to all fields
1994 */
Mark Slee9cb7c612006-09-01 22:17:45 +00001995void t_php_generator::generate_serialize_struct(ofstream &out,
1996 t_struct* tstruct,
1997 string prefix) {
Mark Slee5f8237d2006-10-26 04:57:03 +00001998 indent(out) <<
Mark Slee5151c622007-11-06 22:11:29 +00001999 "$xfer += $" << prefix << "->write($output);" << endl;
Mark Slee6e536442006-06-30 18:28:50 +00002000}
2001
Mark Sleef5377b32006-10-10 01:42:59 +00002002/**
2003 * Writes out a container
2004 */
Mark Slee9cb7c612006-09-01 22:17:45 +00002005void t_php_generator::generate_serialize_container(ofstream &out,
2006 t_type* ttype,
Mark Slee6e536442006-06-30 18:28:50 +00002007 string prefix) {
Mark Slee9cb7c612006-09-01 22:17:45 +00002008 scope_up(out);
Mark Slee5151c622007-11-06 22:11:29 +00002009
Mark Slee6e536442006-06-30 18:28:50 +00002010 if (ttype->is_map()) {
Mark Slee52f643d2006-08-09 00:03:43 +00002011 if (binary_inline_) {
Mark Slee9cb7c612006-09-01 22:17:45 +00002012 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00002013 indent() << "$output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_key_type()) << ");" << endl <<
2014 indent() << "$output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_val_type()) << ");" << endl <<
2015 indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00002016 } else {
Mark Slee9cb7c612006-09-01 22:17:45 +00002017 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +00002018 "$output->writeMapBegin(" <<
Mark Slee52f643d2006-08-09 00:03:43 +00002019 type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
2020 type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
2021 "count($" << prefix << "));" << endl;
2022 }
Mark Slee6e536442006-06-30 18:28:50 +00002023 } else if (ttype->is_set()) {
Mark Slee52f643d2006-08-09 00:03:43 +00002024 if (binary_inline_) {
Mark Slee9cb7c612006-09-01 22:17:45 +00002025 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00002026 indent() << "$output .= pack('c', " << type_to_enum(((t_set*)ttype)->get_elem_type()) << ");" << endl <<
2027 indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00002028
2029 } else {
Mark Slee9cb7c612006-09-01 22:17:45 +00002030 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +00002031 "$output->writeSetBegin(" <<
Mark Slee52f643d2006-08-09 00:03:43 +00002032 type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
2033 "count($" << prefix << "));" << endl;
2034 }
Mark Slee6e536442006-06-30 18:28:50 +00002035 } else if (ttype->is_list()) {
Mark Slee52f643d2006-08-09 00:03:43 +00002036 if (binary_inline_) {
Mark Slee9cb7c612006-09-01 22:17:45 +00002037 out <<
Mark Slee5f8237d2006-10-26 04:57:03 +00002038 indent() << "$output .= pack('c', " << type_to_enum(((t_list*)ttype)->get_elem_type()) << ");" << endl <<
2039 indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
Mark Slee52f643d2006-08-09 00:03:43 +00002040
2041 } else {
Mark Slee9cb7c612006-09-01 22:17:45 +00002042 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +00002043 "$output->writeListBegin(" <<
Mark Slee52f643d2006-08-09 00:03:43 +00002044 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
2045 "count($" << prefix << "));" << endl;
2046 }
Mark Slee6e536442006-06-30 18:28:50 +00002047 }
2048
David Reissd14f4f82008-06-10 22:55:54 +00002049 scope_up(out);
2050
2051 if (ttype->is_map()) {
2052 string kiter = tmp("kiter");
2053 string viter = tmp("viter");
2054 indent(out) <<
2055 "foreach ($" << prefix << " as " <<
2056 "$" << kiter << " => $" << viter << ")" << endl;
Mark Slee9cb7c612006-09-01 22:17:45 +00002057 scope_up(out);
David Reissd14f4f82008-06-10 22:55:54 +00002058 generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
Mark Slee9cb7c612006-09-01 22:17:45 +00002059 scope_down(out);
David Reissd14f4f82008-06-10 22:55:54 +00002060 } else if (ttype->is_set()) {
2061 string iter = tmp("iter");
2062 indent(out) <<
2063 "foreach ($" << prefix << " as $" << iter << " => $true)" << endl;
2064 scope_up(out);
2065 generate_serialize_set_element(out, (t_set*)ttype, iter);
2066 scope_down(out);
2067 } else if (ttype->is_list()) {
2068 string iter = tmp("iter");
2069 indent(out) <<
2070 "foreach ($" << prefix << " as $" << iter << ")" << endl;
2071 scope_up(out);
2072 generate_serialize_list_element(out, (t_list*)ttype, iter);
2073 scope_down(out);
2074 }
2075
2076 scope_down(out);
Mark Slee52f643d2006-08-09 00:03:43 +00002077
2078 if (!binary_inline_) {
Mark Slee6e536442006-06-30 18:28:50 +00002079 if (ttype->is_map()) {
Mark Slee9cb7c612006-09-01 22:17:45 +00002080 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +00002081 "$output->writeMapEnd();" << endl;
Mark Slee6e536442006-06-30 18:28:50 +00002082 } else if (ttype->is_set()) {
Mark Slee9cb7c612006-09-01 22:17:45 +00002083 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +00002084 "$output->writeSetEnd();" << endl;
Mark Slee6e536442006-06-30 18:28:50 +00002085 } else if (ttype->is_list()) {
Mark Slee9cb7c612006-09-01 22:17:45 +00002086 indent(out) <<
Mark Slee5f8237d2006-10-26 04:57:03 +00002087 "$output->writeListEnd();" << endl;
Mark Slee6e536442006-06-30 18:28:50 +00002088 }
Mark Slee52f643d2006-08-09 00:03:43 +00002089 }
Mark Slee5151c622007-11-06 22:11:29 +00002090
2091 scope_down(out);
Mark Slee6e536442006-06-30 18:28:50 +00002092}
2093
2094/**
2095 * Serializes the members of a map.
2096 *
2097 */
Mark Slee9cb7c612006-09-01 22:17:45 +00002098void t_php_generator::generate_serialize_map_element(ofstream &out,
2099 t_map* tmap,
2100 string kiter,
2101 string viter) {
Mark Slee6e536442006-06-30 18:28:50 +00002102 t_field kfield(tmap->get_key_type(), kiter);
Mark Slee9cb7c612006-09-01 22:17:45 +00002103 generate_serialize_field(out, &kfield, "");
Mark Slee6e536442006-06-30 18:28:50 +00002104
2105 t_field vfield(tmap->get_val_type(), viter);
Mark Slee9cb7c612006-09-01 22:17:45 +00002106 generate_serialize_field(out, &vfield, "");
Mark Slee6e536442006-06-30 18:28:50 +00002107}
2108
2109/**
2110 * Serializes the members of a set.
2111 */
Mark Slee9cb7c612006-09-01 22:17:45 +00002112void t_php_generator::generate_serialize_set_element(ofstream &out,
2113 t_set* tset,
2114 string iter) {
Mark Slee6e536442006-06-30 18:28:50 +00002115 t_field efield(tset->get_elem_type(), iter);
Mark Slee9cb7c612006-09-01 22:17:45 +00002116 generate_serialize_field(out, &efield, "");
Mark Slee6e536442006-06-30 18:28:50 +00002117}
2118
2119/**
2120 * Serializes the members of a list.
2121 */
Mark Slee9cb7c612006-09-01 22:17:45 +00002122void t_php_generator::generate_serialize_list_element(ofstream &out,
2123 t_list* tlist,
Mark Slee6e536442006-06-30 18:28:50 +00002124 string iter) {
2125 t_field efield(tlist->get_elem_type(), iter);
Mark Slee9cb7c612006-09-01 22:17:45 +00002126 generate_serialize_field(out, &efield, "");
Mark Slee6e536442006-06-30 18:28:50 +00002127}
2128
2129/**
Mark Slee6e536442006-06-30 18:28:50 +00002130 * Declares a field, which may include initialization as necessary.
2131 *
2132 * @param ttype The type
2133 */
2134string t_php_generator::declare_field(t_field* tfield, bool init, bool obj) {
2135 string result = "$" + tfield->get_name();
2136 if (init) {
David Reisse087a302007-08-23 21:43:25 +00002137 t_type* type = get_true_type(tfield->get_type());
Mark Slee6e536442006-06-30 18:28:50 +00002138 if (type->is_base_type()) {
2139 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2140 switch (tbase) {
2141 case t_base_type::TYPE_VOID:
2142 break;
2143 case t_base_type::TYPE_STRING:
2144 result += " = ''";
2145 break;
Mark Slee78f58e22006-09-02 04:17:07 +00002146 case t_base_type::TYPE_BOOL:
2147 result += " = false";
2148 break;
Mark Slee6e536442006-06-30 18:28:50 +00002149 case t_base_type::TYPE_BYTE:
Mark Slee9cb7c612006-09-01 22:17:45 +00002150 case t_base_type::TYPE_I16:
Mark Slee6e536442006-06-30 18:28:50 +00002151 case t_base_type::TYPE_I32:
Mark Slee6e536442006-06-30 18:28:50 +00002152 case t_base_type::TYPE_I64:
Mark Slee6e536442006-06-30 18:28:50 +00002153 result += " = 0";
2154 break;
Mark Sleec98d0502006-09-06 02:42:25 +00002155 case t_base_type::TYPE_DOUBLE:
2156 result += " = 0.0";
2157 break;
Mark Slee6e536442006-06-30 18:28:50 +00002158 default:
David Reissdd7796f2007-08-28 21:09:06 +00002159 throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase);
Mark Slee6e536442006-06-30 18:28:50 +00002160 }
2161 } else if (type->is_enum()) {
2162 result += " = 0";
2163 } else if (type->is_container()) {
2164 result += " = array()";
Mark Sleefc89d392006-09-04 00:04:39 +00002165 } else if (type->is_struct() || type->is_xception()) {
Mark Slee6e536442006-06-30 18:28:50 +00002166 if (obj) {
Mark Sleee888b372007-01-12 01:06:24 +00002167 result += " = new " + php_namespace(type->get_program()) + type->get_name() + "()";
Mark Slee6e536442006-06-30 18:28:50 +00002168 } else {
2169 result += " = null";
2170 }
2171 }
2172 }
2173 return result + ";";
2174}
2175
2176/**
2177 * Renders a function signature of the form 'type name(args)'
2178 *
2179 * @param tfunction Function definition
2180 * @return String of rendered function definition
2181 */
2182string t_php_generator::function_signature(t_function* tfunction,
2183 string prefix) {
2184 return
2185 prefix + tfunction->get_name() +
2186 "(" + argument_list(tfunction->get_arglist()) + ")";
2187}
2188
2189/**
2190 * Renders a field list
2191 */
2192string t_php_generator::argument_list(t_struct* tstruct) {
2193 string result = "";
2194
2195 const vector<t_field*>& fields = tstruct->get_members();
2196 vector<t_field*>::const_iterator f_iter;
2197 bool first = true;
2198 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2199 if (first) {
2200 first = false;
2201 } else {
2202 result += ", ";
2203 }
2204 result += "$" + (*f_iter)->get_name();
2205 }
2206 return result;
2207}
2208
2209/**
Mark Sleeb1ad0142007-07-10 16:48:37 +00002210 * Gets a typecast string for a particular type.
2211 */
2212string t_php_generator::type_to_cast(t_type* type) {
2213 if (type->is_base_type()) {
2214 t_base_type* btype = (t_base_type*)type;
2215 switch (btype->get_base()) {
2216 case t_base_type::TYPE_BOOL:
2217 return "(bool)";
2218 case t_base_type::TYPE_BYTE:
2219 case t_base_type::TYPE_I16:
2220 case t_base_type::TYPE_I32:
2221 case t_base_type::TYPE_I64:
2222 return "(int)";
2223 case t_base_type::TYPE_DOUBLE:
2224 return "(double)";
2225 case t_base_type::TYPE_STRING:
2226 return "(string)";
2227 default:
2228 return "";
2229 }
2230 } else if (type->is_enum()) {
2231 return "(int)";
2232 }
2233 return "";
2234}
2235
2236/**
Mark Slee6e536442006-06-30 18:28:50 +00002237 * Converts the parse type to a C++ enum string for the given type.
2238 */
2239string t_php_generator ::type_to_enum(t_type* type) {
David Reisse087a302007-08-23 21:43:25 +00002240 type = get_true_type(type);
Mark Slee5151c622007-11-06 22:11:29 +00002241
Mark Slee6e536442006-06-30 18:28:50 +00002242 if (type->is_base_type()) {
2243 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2244 switch (tbase) {
2245 case t_base_type::TYPE_VOID:
2246 throw "NO T_VOID CONSTRUCT";
2247 case t_base_type::TYPE_STRING:
2248 return "TType::STRING";
Mark Slee78f58e22006-09-02 04:17:07 +00002249 case t_base_type::TYPE_BOOL:
2250 return "TType::BOOL";
Mark Slee6e536442006-06-30 18:28:50 +00002251 case t_base_type::TYPE_BYTE:
2252 return "TType::BYTE";
Mark Slee9cb7c612006-09-01 22:17:45 +00002253 case t_base_type::TYPE_I16:
2254 return "TType::I16";
Mark Slee6e536442006-06-30 18:28:50 +00002255 case t_base_type::TYPE_I32:
2256 return "TType::I32";
Mark Slee6e536442006-06-30 18:28:50 +00002257 case t_base_type::TYPE_I64:
2258 return "TType::I64";
Mark Sleec98d0502006-09-06 02:42:25 +00002259 case t_base_type::TYPE_DOUBLE:
2260 return "TType::DOUBLE";
Mark Slee6e536442006-06-30 18:28:50 +00002261 }
2262 } else if (type->is_enum()) {
2263 return "TType::I32";
Mark Sleeb7f58ff2006-09-02 21:59:28 +00002264 } else if (type->is_struct() || type->is_xception()) {
Mark Slee6e536442006-06-30 18:28:50 +00002265 return "TType::STRUCT";
2266 } else if (type->is_map()) {
2267 return "TType::MAP";
2268 } else if (type->is_set()) {
2269 return "TType::SET";
2270 } else if (type->is_list()) {
2271 return "TType::LST";
2272 }
2273
2274 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2275}
David Reissa9ea68b2009-02-17 20:28:24 +00002276
2277THRIFT_REGISTER_GENERATOR(php, "PHP",
2278" inlined: Generate PHP inlined files\n"
2279" server: Generate PHP server stubs\n"
2280" autoload: Generate PHP with autoload\n"
2281" oop: Generate PHP with object oriented subclasses\n"
2282" rest: Generate PHP REST processors\n"
2283);