void t_hack_generator::_generate_recvImpl()

in thrift/compiler/generate/t_hack_generator.cc [5756:5955]


void t_hack_generator::_generate_recvImpl(
    std::ofstream& out,
    const t_service* tservice,
    const t_function* tfunction) {
  auto ttype = tfunction->get_returntype();
  std::string return_typehint;
  std::string resultname;
  std::string recvImpl_method_name;
  bool is_void = false;
  if (const auto* tstream = dynamic_cast<const t_stream_response*>(ttype)) {
    _generate_stream_decode_recvImpl(out, tservice, tfunction);

    resultname = generate_function_helper_name(
        tservice, tfunction, PhpFunctionNameSuffix::FIRST_RESPONSE);

    recvImpl_method_name =
        std::string("recvImpl_") + tfunction->name() + "_FirstResponse";

    if (tstream->has_first_response()) {
      ttype = tstream->get_first_response_type();
      return_typehint = type_to_typehint(ttype);
    } else {
      return_typehint = "void";
      is_void = true;
    }
  } else if (const auto* tsink = dynamic_cast<const t_sink*>(ttype)) {
    _generate_sink_final_response_decode_recvImpl(out, tservice, tfunction);

    resultname = generate_function_helper_name(
        tservice, tfunction, PhpFunctionNameSuffix::FIRST_RESPONSE);

    recvImpl_method_name =
        std::string("recvImpl_") + tfunction->name() + "_FirstResponse";

    if (tsink->sink_has_first_response()) {
      ttype = tsink->get_first_response_type();
      return_typehint = type_to_typehint(ttype);
    } else {
      return_typehint = "void";
      is_void = true;
    }
  } else {
    resultname = generate_function_helper_name(
        tservice, tfunction, PhpFunctionNameSuffix::RESULT);
    recvImpl_method_name = std::string("recvImpl_") + tfunction->name();
    return_typehint = type_to_typehint(ttype);

    is_void = ttype->is_void();
  }

  const std::string& rpc_function_name =
      generate_rpc_function_name(tservice, tfunction);

  t_function recv_function(
      tfunction->get_returntype(),
      recvImpl_method_name,
      std::make_unique<t_paramlist>(program_));

  // Open function
  out << "\n";
  out << indent() << "protected function "
      << function_signature(
             &recv_function,
             "?int $expectedsequenceid = null"
             ", shape(?'read_options' => int) $options = shape()",
             return_typehint)
      << " {\n";
  indent_up();

  out << indent() << "try {\n";
  indent_up();

  out << indent() << "$this->eventHandler_->preRecv('" << rpc_function_name
      << "', $expectedsequenceid);\n";

  out << indent() << "if ($this->input_ is \\TBinaryProtocolAccelerated) {\n";

  indent_up();

  out << indent() << "$result = \\thrift_protocol_read_binary("
      << "$this->input_"
      << ", '" << resultname << "'"
      << ", $this->input_->isStrictRead()"
      << ", Shapes::idx($options, 'read_options', 0)"
      << ");\n";

  indent_down();

  out << indent()
      << "} else if ($this->input_ is \\TCompactProtocolAccelerated)\n";
  scope_up(out);
  out << indent() << "$result = \\thrift_protocol_read_compact("
      << "$this->input_"
      << ", '" << resultname << "'"
      << ", Shapes::idx($options, 'read_options', 0)"
      << ");\n";
  scope_down(out);

  out << indent() << "else\n";
  scope_up(out);

  out << indent() << "$rseqid = 0;\n"
      << indent() << "$fname = '';\n"
      << indent() << "$mtype = 0;\n\n";

  out << indent() << "$this->input_->readMessageBegin(\n"
      << indent() << "  inout $fname,\n"
      << indent() << "  inout $mtype,\n"
      << indent() << "  inout $rseqid,\n"
      << indent() << ");\n"
      << indent() << "if ($mtype === \\TMessageType::EXCEPTION) {\n"
      << indent() << "  $x = new \\TApplicationException();\n"
      << indent() << "  $x->read($this->input_);\n"
      << indent() << "  $this->input_->readMessageEnd();\n"
      << indent() << "  throw $x;\n"
      << indent() << "}\n";

  out << indent() << "$result = " << resultname << "::withDefaultValues();\n"
      << indent() << "$result->read($this->input_);\n";

  out << indent() << "$this->input_->readMessageEnd();\n";

  out << indent()
      << "if ($expectedsequenceid !== null && ($rseqid !== $expectedsequenceid)) {\n"
      << indent() << "  throw new \\TProtocolException(\"" << tfunction->name()
      << " failed: sequence id is out of order\");\n"
      << indent() << "}\n";

  scope_down(out);
  indent_down();
  indent(out) << "} catch (\\THandlerShortCircuitException $ex) {\n";
  indent_up();
  out << indent() << "switch ($ex->resultType) {\n"
      << indent() << "  case \\THandlerShortCircuitException::R_EXPECTED_EX:\n"
      << indent() << "    $this->eventHandler_->recvException('"
      << rpc_function_name << "', $expectedsequenceid, $ex->result);\n"
      << indent() << "    throw $ex->result;\n"
      << indent()
      << "  case \\THandlerShortCircuitException::R_UNEXPECTED_EX:\n"
      << indent() << "    $this->eventHandler_->recvError('"
      << rpc_function_name << "', $expectedsequenceid, $ex->result);\n"
      << indent() << "    throw $ex->result;\n"
      << indent() << "  case \\THandlerShortCircuitException::R_SUCCESS:\n"
      << indent() << "  default:\n"
      << indent() << "    $this->eventHandler_->postRecv('" << rpc_function_name
      << "', $expectedsequenceid, $ex->result);\n"
      << indent() << "    return";

  if (!is_void) {
    out << " $ex->result";
  }
  out << ";\n" << indent() << "}\n";
  indent_down();
  out << indent() << "} catch (\\Exception $ex) {\n";
  indent_up();
  out << indent() << "$this->eventHandler_->recvError('" << rpc_function_name
      << "', $expectedsequenceid, $ex);\n"
      << indent() << "throw $ex;\n";
  indent_down();
  out << indent() << "}\n";

  // Careful, only return result if not a void function
  if (!is_void) {
    out << indent() << "if ($result->success !== null) {\n"
        << indent() << "  $success = $result->success;\n"
        << indent() << "  $this->eventHandler_->postRecv('" << rpc_function_name
        << "', $expectedsequenceid, $success);"
        << "\n"
        << indent() << "  return $success;\n"
        << indent() << "}\n";
  }

  for (const auto& x : tfunction->get_xceptions()->fields()) {
    out << indent() << "if ($result->" << x.name() << " !== null) {\n"
        << indent() << "  $x = $result->" << x.name() << ";"
        << "\n"
        << indent() << "  $this->eventHandler_->recvException('"
        << rpc_function_name << "', $expectedsequenceid, $x);\n"
        << indent() << "  throw $x;\n"
        << indent() << "}\n";
  }

  // Careful, only return _result if not a void function
  if (is_void) {
    out << indent() << "$this->eventHandler_->postRecv('" << rpc_function_name
        << "', $expectedsequenceid, null);\n"
        << indent() << "return;\n";
  } else {
    out << indent() << "$x = new \\TApplicationException(\""
        << tfunction->name() << " failed: unknown result\""
        << ", \\TApplicationException::MISSING_RESULT"
        << ");\n"
        << indent() << "$this->eventHandler_->recvError('" << rpc_function_name
        << "', $expectedsequenceid, $x);\n"
        << indent() << "throw $x;\n";
  }

  // Close function
  scope_down(out);
}