void t_php_generator::generate_service_client()

in compiler/cpp/src/thrift/generate/t_php_generator.cc [1844:2104]


void t_php_generator::generate_service_client(t_service* tservice) {
  ofstream_with_content_based_conditional_update& f_service_client = f_service_;
  if (!classmap_) {
    string f_service_client_name = package_dir_ + service_name_ + "Client.php";
    f_service_client.open(f_service_client_name.c_str());
    generate_service_header(tservice, f_service_client);
  }

  string extends = "";
  string extends_client = "";
  if (tservice->get_extends() != nullptr) {
    extends = tservice->get_extends()->get_name();
    extends_client = " extends " + php_namespace(tservice->get_extends()->get_program()) + extends
                     + "Client";
  }

  f_service_client << "class " << php_namespace_declaration(tservice) << "Client" << extends_client
             << " implements " << php_namespace(tservice->get_program()) << service_name_ << "If" << '\n'
             <<"{"<< '\n';
  indent_up();

  // Private members
  if (extends.empty()) {
    f_service_client << indent() << "protected $input_ = null;" << '\n' << indent()
               << "protected $output_ = null;" << '\n' << '\n';
    f_service_client << indent() << "protected $seqid_ = 0;" << '\n' << '\n';
  }

  // Constructor function
  f_service_client << indent() << "public function __construct($input, $output = null)" << '\n'
                   << indent() << "{" << '\n';

  indent_up();
  if (!extends.empty()) {
    f_service_client << indent() << "parent::__construct($input, $output);" << '\n';
  } else {
    f_service_client << indent() << "$this->input_ = $input;" << '\n'
                     << indent() << "$this->output_ = $output ? $output : $input;" << '\n';
  }

  indent_down();
  f_service_client << indent() << "}" << '\n' << '\n';

  // Generate client method implementations
  vector<t_function*> functions = tservice->get_functions();
  vector<t_function*>::const_iterator f_iter;
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    t_struct* arg_struct = (*f_iter)->get_arglist();
    const vector<t_field*>& fields = arg_struct->get_members();
    vector<t_field*>::const_iterator fld_iter;
    string funname = (*f_iter)->get_name();

    f_service_client << '\n';

    // Open function
    indent(f_service_client) << "public function " << function_signature(*f_iter) << '\n';
    scope_up(f_service_client);
    indent(f_service_client) << "$this->send_" << funname << "(";

    bool first = true;
    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
      if (first) {
        first = false;
      } else {
        f_service_client << ", ";
      }
      f_service_client << "$" << (*fld_iter)->get_name();
    }
    f_service_client << ");" << '\n';

    if (!(*f_iter)->is_oneway()) {
      f_service_client << indent();
      if (!(*f_iter)->get_returntype()->is_void()) {
        f_service_client << "return ";
      }
      f_service_client << "$this->recv_" << funname << "();" << '\n';
    }
    scope_down(f_service_client);
    f_service_client << '\n';

    indent(f_service_client) << "public function send_" << function_signature(*f_iter) << '\n';
    scope_up(f_service_client);

    std::string argsname = php_namespace(tservice->get_program()) + service_name_ + "_"
                           + (*f_iter)->get_name() + "_args";

    f_service_client << indent() << "$args = new " << argsname << "();" << '\n';

    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
      f_service_client << indent() << "$args->" << (*fld_iter)->get_name() << " = $"
                 << (*fld_iter)->get_name() << ";" << '\n';
    }

    f_service_client << indent() << "$bin_accel = ($this->output_ instanceof "
               << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');"
               << '\n';

    f_service_client << indent() << "if ($bin_accel) {" << '\n';
    indent_up();

    string messageType = (*f_iter)->is_oneway() ? "TMessageType::ONEWAY" : "TMessageType::CALL";

    f_service_client << indent() << "thrift_protocol_write_binary(" << '\n';

    indent_up();
    f_service_client << indent() << "$this->output_," << '\n'
               << indent() << "'" << (*f_iter)->get_name() << "'," << '\n'
               << indent() << messageType << "," << '\n'
               << indent() << "$args," << '\n'
               << indent() << "$this->seqid_," << '\n'
               << indent() << "$this->output_->isStrictWrite()" << '\n';

    indent_down();
    f_service_client << indent() << ");" << '\n';

    indent_down();
    f_service_client << indent() << "} else {" << '\n';
    indent_up();

    // Serialize the request header
    if (binary_inline_) {
      f_service_client << indent() << "$buff = pack('N', (0x80010000 | " << messageType << "));" << '\n'
                       << indent() << "$buff .= pack('N', strlen('" << funname << "'));" << '\n'
                       << indent() << "$buff .= '" << funname << "';" << '\n' << indent()
                       << "$buff .= pack('N', $this->seqid_);" << '\n';
    } else {
      f_service_client << indent() << "$this->output_->writeMessageBegin('" << (*f_iter)->get_name()
                       << "', " << messageType << ", $this->seqid_);" << '\n';
    }

    // Write to the stream
    if (binary_inline_) {
      f_service_client << indent() << "$args->write($buff);" << '\n' << indent()
                       << "$this->output_->write($buff);" << '\n' << indent()
                       << "$this->output_->flush();" << '\n';
    } else {
      f_service_client << indent() << "$args->write($this->output_);" << '\n' << indent()
                       << "$this->output_->writeMessageEnd();" << '\n' << indent()
                       << "$this->output_->getTransport()->flush();" << '\n';
    }

    scope_down(f_service_client);

    scope_down(f_service_client);

    if (!(*f_iter)->is_oneway()) {
      std::string resultname = php_namespace(tservice->get_program()) + service_name_ + "_"
                               + (*f_iter)->get_name() + "_result";
      t_struct noargs(program_);

      t_function recv_function((*f_iter)->get_returntype(),
                               string("recv_") + (*f_iter)->get_name(),
                               &noargs);
      // Open function
      f_service_client << '\n' << indent() << "public function " << function_signature(&recv_function)
                       << '\n';
      scope_up(f_service_client);

      f_service_client << indent() << "$bin_accel = ($this->input_ instanceof "
                       << "TBinaryProtocolAccelerated)"
                       << " && function_exists('thrift_protocol_read_binary');" << '\n';

      f_service_client << indent() << "if ($bin_accel) {" << '\n';

      indent_up();
      f_service_client << indent() << "$result = thrift_protocol_read_binary(" << '\n';

      indent_up();
      f_service_client << indent() << "$this->input_," << '\n'
                       << indent() << "'" << resultname << "'," << '\n'
                       << indent() << "$this->input_->isStrictRead()" << '\n';

      indent_down();
      f_service_client << indent() << ");" << '\n';

      indent_down();
      f_service_client << indent() << "} else {" << '\n';

      indent_up();
      f_service_client << indent() << "$rseqid = 0;" << '\n'
                       << indent() << "$fname = null;" << '\n'
                       << indent() << "$mtype = 0;" << '\n' << '\n';

      if (binary_inline_) {
        t_field ffname(g_type_string, "fname");
        t_field fseqid(g_type_i32, "rseqid");
        f_service_client << indent() << "$ver = unpack('N', $this->input_->readAll(4));" << '\n'
                         << indent() << "$ver = $ver[1];" << '\n' << indent() << "$mtype = $ver & 0xff;"
                         << '\n' << indent() << "$ver = $ver & 0xffff0000;" << '\n' << indent()
                         << "if ($ver != 0x80010000) throw new "
                         << "TProtocolException('Bad version identifier: '.$ver, "
                         << "TProtocolException::BAD_VERSION);" << '\n';
        generate_deserialize_field(f_service_client, &ffname, "", true);
        generate_deserialize_field(f_service_client, &fseqid, "", true);
      } else {
        f_service_client << indent() << "$this->input_->readMessageBegin($fname, $mtype, $rseqid);" << '\n'
                         << indent() << "if ($mtype == TMessageType::EXCEPTION) {" << '\n';

        indent_up();
        f_service_client << indent() << "$x = new TApplicationException();" << '\n'
                         << indent() << "$x->read($this->input_);" << '\n'
                         << indent() << "$this->input_->readMessageEnd();" << '\n'
                         << indent() << "throw $x;" << '\n';
        indent_down();
        f_service_client << indent() << "}" << '\n';
      }

      f_service_client << indent() << "$result = new " << resultname << "();" << '\n'
                       << indent() << "$result->read($this->input_);" << '\n';

      if (!binary_inline_) {
        f_service_client << indent() << "$this->input_->readMessageEnd();" << '\n';
      }

      scope_down(f_service_client);

      // Careful, only return result if not a void function
      if (!(*f_iter)->get_returntype()->is_void()) {
        f_service_client << indent() << "if ($result->success !== null) {" << '\n';

        indent_up();
        f_service_client << indent() << "return $result->success;" << '\n';

        indent_down();
        f_service_client << indent() << "}" << '\n';
      }

      t_struct* xs = (*f_iter)->get_xceptions();
      const std::vector<t_field*>& xceptions = xs->get_members();
      vector<t_field*>::const_iterator x_iter;
      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
        f_service_client << indent() << "if ($result->" << (*x_iter)->get_name() << " !== null) {" << '\n';

        indent_up();
        f_service_client << indent() << "throw $result->" << (*x_iter)->get_name() << ";" << '\n';

        indent_down();
        f_service_client << indent() << "}" << '\n';
      }

      // Careful, only return _result if not a void function
      if ((*f_iter)->get_returntype()->is_void()) {
        indent(f_service_client) << "return;" << '\n';
      } else {
        f_service_client << indent() << "throw new \\Exception(\"" << (*f_iter)->get_name()
                         << " failed: unknown result\");" << '\n';
      }

      // Close function
      scope_down(f_service_client);
    }
  }

  indent_down();
  f_service_client << "}" << '\n';

  // Close service client file
  if (!classmap_) {
    f_service_client.close();
  }
}