mirror of
https://github.com/bdnugget/magento2.git
synced 2026-11-07 09:17:35 +00:00
421 lines
12 KiB
PHP
421 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* Magento-specific SOAP fault.
|
|
*
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
namespace Magento\Webapi\Model\Soap;
|
|
|
|
use Magento\Framework\App\State;
|
|
use Magento\Framework\Escaper;
|
|
use Magento\Framework\App\ObjectManager;
|
|
|
|
/**
|
|
* Webapi Fault Model for Soap.
|
|
*/
|
|
class Fault
|
|
{
|
|
const FAULT_REASON_INTERNAL = 'Internal Error.';
|
|
|
|
/**#@+
|
|
* Fault codes that are used in SOAP faults.
|
|
*/
|
|
const FAULT_CODE_SENDER = 'Sender';
|
|
const FAULT_CODE_RECEIVER = 'Receiver';
|
|
|
|
/**#@+
|
|
* Nodes that can appear in Detail node of SOAP fault.
|
|
*/
|
|
const NODE_DETAIL_PARAMETERS = 'Parameters';
|
|
const NODE_DETAIL_WRAPPED_ERRORS = 'WrappedErrors';
|
|
const NODE_DETAIL_WRAPPED_EXCEPTION = 'WrappedException';
|
|
/* Note that parameter node must be unique in scope of all complex types declared in WSDL */
|
|
const NODE_DETAIL_PARAMETER = 'GenericFaultParameter';
|
|
const NODE_DETAIL_PARAMETER_KEY = 'key';
|
|
const NODE_DETAIL_PARAMETER_VALUE = 'value';
|
|
const NODE_DETAIL_WRAPPED_ERROR = 'WrappedError';
|
|
const NODE_DETAIL_WRAPPED_ERROR_MESSAGE = 'message';
|
|
const NODE_DETAIL_WRAPPED_ERROR_PARAMETERS = 'parameters';
|
|
const NODE_DETAIL_WRAPPED_ERROR_PARAMETER = 'parameter';
|
|
const NODE_DETAIL_WRAPPED_ERROR_KEY = 'key';
|
|
const NODE_DETAIL_WRAPPED_ERROR_VALUE = 'value';
|
|
const NODE_DETAIL_TRACE = 'Trace';
|
|
const NODE_DETAIL_WRAPPER = 'GenericFault';
|
|
/**#@-*/
|
|
|
|
/**
|
|
* @var Escaper
|
|
*/
|
|
private $escaper;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected $_soapFaultCode;
|
|
|
|
/**
|
|
* Parameters are extracted from exception and can be inserted into 'Detail' node as 'Parameters'.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_parameters = [];
|
|
|
|
/**
|
|
* Wrapped errors are extracted from exception and can be inserted into 'Detail' node as 'WrappedErrors'.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_wrappedErrors = [];
|
|
|
|
/**
|
|
* Fault name is used for details wrapper node name generation.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_faultName = '';
|
|
|
|
/**
|
|
* Details that are used to generate 'Detail' node of SoapFault.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_details = [];
|
|
|
|
/**
|
|
* @var \Magento\Framework\App\RequestInterface
|
|
*/
|
|
protected $_request;
|
|
|
|
/**
|
|
* @var Server
|
|
*/
|
|
protected $_soapServer;
|
|
|
|
/**
|
|
* @var \Magento\Framework\Locale\ResolverInterface
|
|
*/
|
|
protected $_localeResolver;
|
|
|
|
/**
|
|
* @var \Magento\Framework\App\State
|
|
*/
|
|
protected $appState;
|
|
|
|
/**
|
|
* @var null|string
|
|
*/
|
|
protected $stackTrace;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected $message;
|
|
|
|
/**
|
|
* @param \Magento\Framework\App\RequestInterface $request
|
|
* @param Server $soapServer
|
|
* @param \Magento\Framework\Webapi\Exception $exception
|
|
* @param \Magento\Framework\Locale\ResolverInterface $localeResolver
|
|
* @param State $appState
|
|
* @param Escaper|null $escaper
|
|
*/
|
|
public function __construct(
|
|
\Magento\Framework\App\RequestInterface $request,
|
|
Server $soapServer,
|
|
\Magento\Framework\Webapi\Exception $exception,
|
|
\Magento\Framework\Locale\ResolverInterface $localeResolver,
|
|
State $appState,
|
|
Escaper $escaper = null
|
|
) {
|
|
$this->_soapFaultCode = $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;
|
|
$this->escaper = $escaper ?? ObjectManager::getInstance()->get(
|
|
Escaper::class
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Render exception as XML.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function toXml()
|
|
{
|
|
if ($this->appState->getMode() == State::MODE_DEVELOPER) {
|
|
$this->addDetails([self::NODE_DETAIL_TRACE => "<![CDATA[{$this->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->_soapFaultCode;
|
|
}
|
|
|
|
/**
|
|
* Retrieve SOAP fault language.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getLanguage()
|
|
{
|
|
return \Locale::getPrimaryLanguage($this->_localeResolver->getLocale());
|
|
}
|
|
|
|
/**
|
|
* Retrieve message
|
|
*
|
|
* @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 = <<<FAULT_MESSAGE
|
|
<?xml version="1.0" encoding="utf-8" ?>
|
|
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" $detailsNamespace>
|
|
<env:Body>
|
|
<env:Fault>
|
|
<env:Code>
|
|
<env:Value>env:$code</env:Value>
|
|
</env:Code>
|
|
<env:Reason>
|
|
<env:Text xml:lang="$language">$reason</env:Text>
|
|
</env:Reason>
|
|
$detailXml
|
|
</env:Fault>
|
|
</env:Body>
|
|
</env:Envelope>
|
|
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 = "<env:Detail><m:{$errorDetailsNode}>"
|
|
. $detailsXml . "</m:{$errorDetailsNode}></env:Detail>";
|
|
} 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 = $this->escaper->escapeHtml($detailNode);
|
|
if (is_numeric($detailNode)) {
|
|
continue;
|
|
}
|
|
switch ($detailNode) {
|
|
case self::NODE_DETAIL_TRACE:
|
|
if (is_string($detailValue) || is_numeric($detailValue)) {
|
|
$detailsXml .= "<m:{$detailNode}>" . $this->escaper->escapeHtml($detailValue) .
|
|
"</m:{$detailNode}>";
|
|
}
|
|
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 .= "<m:$parameterNode><m:$keyNode>$parameterName</m:$keyNode><m:$valueNode>"
|
|
. $this->escaper->escapeHtml($parameterValue) . "</m:$valueNode></m:$parameterNode>";
|
|
}
|
|
}
|
|
if (!empty($paramsXml)) {
|
|
$parametersNode = self::NODE_DETAIL_PARAMETERS;
|
|
$result = "<m:$parametersNode>" . $paramsXml . "</m:$parametersNode>";
|
|
}
|
|
|
|
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 = "<m:$wrappedErrorsNode>" . $errorsXml . "</m:$wrappedErrorsNode>";
|
|
}
|
|
|
|
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 = "<m:$wrappedErrorNode><m:$messageNode>$rawMessage</m:$messageNode>";
|
|
|
|
if (!empty($parameters)) {
|
|
$parametersNode = self::NODE_DETAIL_WRAPPED_ERROR_PARAMETERS;
|
|
$xml .= "<m:$parametersNode>";
|
|
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 .= "<m:$parameterNode>" .
|
|
"<m:$keyNode>$key</m:$keyNode><m:$valueNode>$value</m:$valueNode>" .
|
|
"</m:$parameterNode>";
|
|
}
|
|
$xml .= "</m:$parametersNode>";
|
|
}
|
|
$xml .= "</m:$wrappedErrorNode>";
|
|
|
|
return $xml;
|
|
}
|
|
}
|