_soapCode = $exception->getOriginator(); $this->_parameters = $exception->getDetails(); $this->_wrappedErrors = $exception->getErrors(); $this->stackTrace = $exception->getStackTrace() ?: $exception->getTraceAsString(); $this->message = $exception->getMessage(); $this->_request = $request; $this->_soapServer = $soapServer; $this->_localeResolver = $localeResolver; $this->appState = $appState; } /** * Render exception as XML. * * @return string */ public function toXml() { if ($this->appState->getMode() == State::MODE_DEVELOPER) { $this->addDetails([self::NODE_DETAIL_TRACE => "stackTrace}]]>"]); } if ($this->getParameters()) { $this->addDetails([self::NODE_DETAIL_PARAMETERS => $this->getParameters()]); } if ($this->getWrappedErrors()) { $this->addDetails([self::NODE_DETAIL_WRAPPED_ERRORS => $this->getWrappedErrors()]); } return $this->getSoapFaultMessage($this->getMessage(), $this->getSoapCode(), $this->getDetails()); } /** * Retrieve additional details about current fault. * * @return array */ public function getParameters() { return $this->_parameters; } /** * Retrieve wrapped errors about current fault. * * @return array */ public function getWrappedErrors() { return $this->_wrappedErrors; } /** * Add details about current fault. * * @param array $details Associative array containing details about current fault * @return $this */ public function addDetails($details) { $this->_details = array_merge($this->_details, $details); return $this; } /** * Retrieve additional details about current fault. * * @return array */ public function getDetails() { return $this->_details; } /** * Retrieve SOAP fault code. * * @return string */ public function getSoapCode() { return $this->_soapCode; } /** * Retrieve SOAP fault language. * * @return string */ public function getLanguage() { return \Locale::getPrimaryLanguage($this->_localeResolver->getLocale()); } /** * @return string */ public function getMessage() { return $this->message; } /** * Generate SOAP fault message in XML format. * * @param string $reason Human-readable explanation of the fault * @param string $code SOAP fault code * @param array|null $details Detailed reason message(s) * @return string */ public function getSoapFaultMessage($reason, $code, $details = null) { $detailXml = $this->_generateDetailXml($details); $language = $this->getLanguage(); $detailsNamespace = !empty($detailXml) ? 'xmlns:m="' . urlencode($this->_soapServer->generateUri(true)) . '"' : ''; $reason = htmlentities($reason); $message = << env:$code $reason $detailXml FAULT_MESSAGE; return $message; } /** * Generate 'Detail' node content. * * In case when fault name is undefined, no 'Detail' node is generated. * * @param array $details * @return string */ protected function _generateDetailXml($details) { $detailsXml = ''; if (is_array($details) && !empty($details)) { $detailsXml = $this->_convertDetailsToXml($details); if ($detailsXml) { $errorDetailsNode = self::NODE_DETAIL_WRAPPER; $detailsXml = "" . $detailsXml . ""; } else { $detailsXml = ''; } } return $detailsXml; } /** * Recursively convert details array into XML structure. * * @param array $details * @return string */ protected function _convertDetailsToXml($details) { $detailsXml = ''; foreach ($details as $detailNode => $detailValue) { $detailNode = htmlspecialchars($detailNode); if (is_numeric($detailNode)) { continue; } switch ($detailNode) { case self::NODE_DETAIL_TRACE: if (is_string($detailValue) || is_numeric($detailValue)) { $detailsXml .= "" . htmlspecialchars($detailValue) . ""; } break; case self::NODE_DETAIL_PARAMETERS: $detailsXml .= $this->_getParametersXml($detailValue); break; case self::NODE_DETAIL_WRAPPED_ERRORS: $detailsXml .= $this->_getWrappedErrorsXml($detailValue); break; } } return $detailsXml; } /** * Generate XML for parameters. * * @param array $parameters * @return string */ protected function _getParametersXml($parameters) { $result = ''; if (!is_array($parameters)) { return $result; } $paramsXml = ''; foreach ($parameters as $parameterName => $parameterValue) { if ((is_string($parameterName) || is_numeric($parameterName)) && (is_string($parameterValue) || is_numeric($parameterValue)) ) { $keyNode = self::NODE_DETAIL_PARAMETER_KEY; $valueNode = self::NODE_DETAIL_PARAMETER_VALUE; $parameterNode = self::NODE_DETAIL_PARAMETER; if (is_numeric($parameterName)) { $parameterName++; } $paramsXml .= "$parameterName" . htmlspecialchars($parameterValue) . ""; } } if (!empty($paramsXml)) { $parametersNode = self::NODE_DETAIL_PARAMETERS; $result = "" . $paramsXml . ""; } return $result; } /** * Generate XML for wrapped errors. * * @param array $wrappedErrors * @return string */ protected function _getWrappedErrorsXml($wrappedErrors) { $result = ''; if (!is_array($wrappedErrors)) { return $result; } $errorsXml = ''; foreach ($wrappedErrors as $error) { $errorsXml .= $this->_generateErrorNodeXml($error); } if (!empty($errorsXml)) { $wrappedErrorsNode = self::NODE_DETAIL_WRAPPED_ERRORS; $result = "" . $errorsXml . ""; } return $result; } /** * Generate XML for a particular error node. * * @param array $error * @return string */ protected function _generateErrorNodeXML($error) { $wrappedErrorNode = self::NODE_DETAIL_WRAPPED_ERROR; $messageNode = self::NODE_DETAIL_WRAPPED_ERROR_MESSAGE; $parameters = $error->getParameters(); $rawMessage = $error->getRawMessage(); $xml = "$rawMessage"; if (!empty($parameters)) { $parametersNode = self::NODE_DETAIL_WRAPPED_ERROR_PARAMETERS; $xml .= ""; foreach ($parameters as $key => $value) { $parameterNode = self::NODE_DETAIL_WRAPPED_ERROR_PARAMETER; $keyNode = self::NODE_DETAIL_PARAMETER_KEY; $valueNode = self::NODE_DETAIL_WRAPPED_ERROR_VALUE; $xml .= "" . "$key$value" . ""; } $xml .= ""; } $xml .= ""; return $xml; } }