vendor/ezsystems/ezcommerce-shop/src/Silversolutions/Bundle/EshopBundle/Services/Transport/TsoWebConnectorMessageTransport.php line 46

Open in your IDE?
  1. <?php
  2. /**
  3.  * @copyright Copyright (C) Ibexa AS. All rights reserved.
  4.  * @license For full copyright and license information view LICENSE file distributed with this source code.
  5.  */
  6. namespace Silversolutions\Bundle\EshopBundle\Services\Transport;
  7. use eZ\Publish\Core\MVC\ConfigResolverInterface;
  8. use Monolog\Logger;
  9. use Silversolutions\Bundle\EshopBundle\Exceptions\ConfigurationException;
  10. use Silversolutions\Bundle\EshopBundle\Exceptions\ErpUnavailableException;
  11. use Silversolutions\Bundle\EshopBundle\Message\AbstractMessage;
  12. use Silversolutions\Bundle\EshopBundle\Serializer\Encoder\DomXmlEncoder;
  13. use Silversolutions\Bundle\EshopBundle\Services\ErpSemaphoreServiceInterface;
  14. use Silversolutions\Bundle\EshopBundle\Services\Mapping\AbstractDocumentMappingService;
  15. use Silversolutions\Utilities\Xml\Converter;
  16. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  17. use Symfony\Component\Serializer\Serializer;
  18. /**
  19.  * This class is the transport implementation, which communicates with the
  20.  * Web-Connector of TSO Data.
  21.  *
  22.  * Currently only the SOAP RPC mode is implemented.
  23.  *
  24.  * Since the PHP SoapClient's API only accepts arrays for structured data
  25.  * transmission, the document objects can not be serialized using the XSD2PHP
  26.  * library. As a consequence a normalizer (PublicAttributeNormalizer) was
  27.  * written, which converts objects to plain PHP arrays and back. That
  28.  * normalizer leverages symfony's serializer API:
  29.  * https://github.com/symfony/Serializer
  30.  *
  31.  * Additionally, if an instance of AbstractDocumentMappingService was injected
  32.  * by the method setMappingService(), the normalized array of the request and
  33.  * response are passed to this mapping service. That means, that the subclass
  34.  * of the mapper must be able to handle array data. For example the
  35.  * XsltDocumentMappingService may be used. If no service was injected, no
  36.  * mapping is done at all.
  37.  *
  38.  * All configuration must be injected using the respective setter methods. These
  39.  * method calls are already defined in the service configuration of the
  40.  * EshopBundle. All default values are defined in the webconnector.yml and may or
  41.  * must be overwritten in the project configuration.
  42.  */
  43. class TsoWebConnectorMessageTransport extends AbstractMessageTransport
  44. {
  45.     /**
  46.      * This is the default value for the SoapClients uri parameter.
  47.      */
  48.     const DEFAULT_URI 'http://www.ibexa.co';
  49.     /**
  50.      * This is the SOAP operation name of the message, which directly sends
  51.      * the ERP's native message format.
  52.      */
  53.     const RAW_MESSAGE 'SV_RAW_MESSAGE';
  54.     /**
  55.      * This is the SOAP operation name of the message, which checks the
  56.      * availability of the ERP system.
  57.      */
  58.     const PING 'SV_ERP_STATUS';
  59.     /**
  60.      * Measuring point code for logging.
  61.      *
  62.      * Specifies the point right before the SOAP communication, after mapping
  63.      * and events.
  64.      */
  65.     const MEASURING_POINT_SOAP_REQUEST '180_soap';
  66.     /**
  67.      * Measuring point code for logging.
  68.      *
  69.      * Specifies the point right after the SOAP communication, before mapping
  70.      * and events.
  71.      */
  72.     const MEASURING_POINT_SOAP_RESPONSE '220_soap';
  73.     const LOG_MESSAGE_SOAP_REQUEST 'ERP transport request (SOAP data)';
  74.     const LOG_MESSAGE_SOAP_RESPONSE 'ERP transport response (SOAP data)';
  75.     /**
  76.      * Optional dependency to a mapping mapping service. If it's not set,
  77.      * mapping is ignored.
  78.      *
  79.      * @see setMappingService()
  80.      *
  81.      * @var AbstractDocumentMappingService
  82.      */
  83.     protected $mappingService;
  84.     /**
  85.      * Setting: Used in non-WSDL mode. The remote location of the targeted
  86.      * service.
  87.      *
  88.      * @see setServiceLocation()
  89.      *
  90.      * @var string
  91.      */
  92.     protected $serviceLocation;
  93.     /**
  94.      * Setting: Used in non-WSDL mode. The URI used as namespace in the SOAP
  95.      * messages.
  96.      *
  97.      * @see setServiceUri()
  98.      *
  99.      * @var string
  100.      */
  101.     protected $serviceUri '';
  102.     /**
  103.      * Setting: Used in WSDL mode. The location of the WSDL file.
  104.      *
  105.      * @see setWsdlLocation()
  106.      *
  107.      * @var string
  108.      */
  109.     protected $wsdlLocation;
  110.     /**
  111.      * Setting: Default parameters for Web-Connector operations.
  112.      *
  113.      * @see setParameters()
  114.      *
  115.      * @var array
  116.      */
  117.     protected $parameters;
  118.     /**
  119.      * @var bool
  120.      */
  121.     protected $allowSelfSigned true;
  122.     /** @var ConfigResolverInterface */
  123.     protected $configResolver;
  124.     /**
  125.      * TsoWebConnectorMessageTransport constructor.
  126.      *
  127.      * @param EventDispatcherInterface $eventDispatcher
  128.      * @param Logger $loggingService
  129.      * @param Logger $erpLogger
  130.      * @param ErpSemaphoreServiceInterface $erpSemaphore
  131.      * @param ConfigResolverInterface $configResolver
  132.      */
  133.     public function __construct(
  134.         EventDispatcherInterface $eventDispatcher,
  135.         Logger $loggingService,
  136.         Logger $erpLogger,
  137.         ErpSemaphoreServiceInterface $erpSemaphore,
  138.         ConfigResolverInterface $configResolver
  139.     ) {
  140.         $this->configResolver $configResolver;
  141.         parent::__construct($eventDispatcher$loggingService$erpLogger$erpSemaphore);
  142.     }
  143.     /**
  144.      * Sets properties.
  145.      */
  146.     public function setProperties()
  147.     {
  148.         //serviceLocation
  149.         $this->serviceLocation $this->configResolver->getParameter('web_connector.service_location''siso_erp');
  150.         //serviceUri
  151.         $this->serviceUri $this->configResolver->getParameter('web_connector.service_uri''siso_erp');
  152.         //parameters
  153.         $this->parameters $this->configResolver->getParameter('web_connector.default_parameters''siso_erp');
  154.         //allowSelfSigned
  155.         $this->allowSelfSigned $this->configResolver->getParameter('web_connector.allow_self_signed_ssl''siso_erp');
  156.     }
  157.     /**
  158.      * The concrete implementation of the communication process to the remote
  159.      * ERP service. In this case the Web-Connector. Please see the class
  160.      * documentation for more details.
  161.      *
  162.      * @param AbstractMessage $message
  163.      * @param array $parameters Currently not used.
  164.      *
  165.      * @throws ErpUnavailableException   If the ERP system is considered to be
  166.      *                                   offline.
  167.      * @throws \UnexpectedValueException If the received response is not valid
  168.      *                                   or configuration is not properly.
  169.      */
  170.     protected function internalSendMessage(
  171.         AbstractMessage $message,
  172.         array $parameters = []
  173.     ) {
  174.         $domSerializer = new DomXmlEncoder($this->logging);
  175.         $normalizers = [$domSerializer];
  176.         $encoders = [$domSerializer];
  177.         $serializer = new Serializer($normalizers$encoders);
  178.         // Normalize request object into an array
  179.         $serializedRequest $serializer->serialize(
  180.             $message->getRequestDocument(),
  181.             DomXmlEncoder::ENCODING_FORMAT
  182.         );
  183.         $soapClientParameters = [
  184.             'location' => $this->determineWebserviceUrl($message),
  185.             'uri' => $this->determineWebserviceUrl($message),
  186.         ];
  187.         $operation $this->determineOperation($message);
  188.         if (!is_string($operation) || $operation === '') {
  189.             throw new \UnexpectedValueException('Injected SOAP operation must be a non empty string.');
  190.         }
  191.         // Map request
  192.         $mappingIdentifier $this->determineMappingIdentifier($message);
  193.         if (is_string($mappingIdentifier) && $mappingIdentifier !== ''
  194.             && $this->mappingService instanceof AbstractDocumentMappingService) {
  195.             $mappedRequest $this->mappingService->mapRequest(
  196.                 $serializedRequest,
  197.                 $mappingIdentifier
  198.             );
  199.         } else {
  200.             if (!$this->mappingService instanceof AbstractDocumentMappingService) {
  201.                 $this->logging->notice(
  202.                     'No valid mapping service is given to the transport. Thus no mapping has been done.'
  203.                 );
  204.             } elseif (!is_string($mappingIdentifier) || $mappingIdentifier === '') {
  205.                 $this->logging->notice(
  206.                     'No valid mapping identifier is given to the transport. Thus no mapping has been done.'
  207.                 );
  208.             }
  209.             $mappedRequest $serializedRequest;
  210.         }
  211.         // Since all data, which is sent to the Web-Connector, must be XML
  212.         // based, it is put into the XML converter. It can determine how to
  213.         // get the necessary array.
  214.         $converter = new Converter($mappedRequest);
  215.         // Append message data to request parameters
  216.         $parameters += $this->parameters;
  217.         if ($operation === self::RAW_MESSAGE) {
  218.             // Raw messages are sent unconverted to the Web-Connector
  219.             $parameters['data'] = $mappedRequest;
  220.         } else {
  221.             $parameters['data'] = $converter->getArray();
  222.         }
  223.         $this->erpLogger->notice(
  224.             self::LOG_MESSAGE_SOAP_REQUEST,
  225.             [
  226.                 'message_identifier' => get_class($message),
  227.                 'message_data' => $parameters,
  228.                 'measuring_point' => self::MEASURING_POINT_SOAP_REQUEST,
  229.                 'soap_parameters' => $soapClientParameters,
  230.             ]
  231.         );
  232.         // Request remote service
  233.         $startTime microtime(true);
  234.         $response $this->invokeSoapRequest(
  235.             $operation,
  236.             $parameters,
  237.             $soapClientParameters,
  238.             $this->determineWebserviceUrl($message)
  239.         );
  240.         $processingTime = (int) ((microtime(true) - $startTime) * 1000);
  241.         // Validate and remove status field, as multiple root elements are not
  242.         // well formed during XML processing
  243.         if ($response === null || !isset($response['status'])) {
  244.             $message->setResponseStatus(AbstractMessage::RESPONSE_STATUS_SERVICE_ERROR);
  245.             $message->setResponseError('Unexpected response from Web-Connector service.');
  246.             $this->logResponse($response$message$processingTime);
  247.             $exceptionMessage 'Response is expected to be an array and contain a "status" element.';
  248.             if (!$this->testCommunication()) {
  249.                 throw new ErpUnavailableException($exceptionMessage);
  250.             } else {
  251.                 throw new \UnexpectedValueException($exceptionMessage);
  252.             }
  253.         } else {
  254.             $isValid $this->validateResponseStatus($response['status'], $message);
  255.             if (!$isValid) {
  256.                 $webConnectorError = isset($response['error'])
  257.                     ? $response['error']
  258.                     : 'No error message available';
  259.                 $erpError = isset($response['erp_message'])
  260.                     ? $response['erp_message']
  261.                     : 'No error message available';
  262.                 $logMessage 'ERP request returned an error.' PHP_EOL 'Web-Connector: "' $webConnectorError
  263.                     PHP_EOL '" ERP: "' $erpError '"';
  264.                 $this->logging->error($logMessage, ['request' => $parameters['data'], 'response' => $response]);
  265.                 $message->setResponseError($logMessage);
  266.                 if (!$this->testCommunication()) {
  267.                     $message->setResponseStatus(AbstractMessage::RESPONSE_STATUS_SERVICE_ERROR);
  268.                     throw new ErpUnavailableException('ERP is unavailable.');
  269.                 } else {
  270.                     $message->setResponseStatus(AbstractMessage::RESPONSE_STATUS_ERP_TIMEOUT);
  271.                 }
  272.                 $message->setResponseDocument(null);
  273.                 $this->logResponse($response$message$processingTime);
  274.                 return;
  275.             }
  276.             $this->logResponse($response$message$processingTime);
  277.             unset($response['status']);
  278.         }
  279.         $responseDocument $this->determineResponseDocument($message);
  280.         if ($responseDocument !== null) {
  281.             $converter = new Converter($response);
  282.             // Map response
  283.             if (is_string($mappingIdentifier) && $mappingIdentifier !== ''
  284.                 && $this->mappingService instanceof AbstractDocumentMappingService) {
  285.                 $mappedResponse $this->mappingService->mapResponse(
  286.                     $converter->getXml(),
  287.                     $mappingIdentifier
  288.                 );
  289.             } else {
  290.                 $mappedResponse $converter->getXml();
  291.             }
  292.             // Denormalize array data into object
  293.             $responseDocument $serializer->deserialize(
  294.                 $mappedResponse,
  295.                 get_class($responseDocument),
  296.                 DomXmlEncoder::ENCODING_FORMAT
  297.             );
  298.         }
  299.         // Append response document to message object reference
  300.         $message->setResponseDocument($responseDocument);
  301.     }
  302.     /**
  303.      * Writes the given ERP response and its meta data to the ERP logger.
  304.      *
  305.      * @param array|null $response
  306.      * @param AbstractMessage $message
  307.      * @param int $processingTime
  308.      */
  309.     private function logResponse($responseAbstractMessage $message$processingTime)
  310.     {
  311.         $logLevel $message->getResponseStatus() === AbstractMessage::RESPONSE_STATUS_OK 'notice' 'error';
  312.         $this->erpLogger->log(
  313.             $logLevel,
  314.             self::LOG_MESSAGE_SOAP_RESPONSE,
  315.             [
  316.                 'message_identifier' => get_class($message),
  317.                 'message_data' => $response,
  318.                 'response_status' => $message->getResponseStatus(),
  319.                 'processing_time' => $processingTime,
  320.                 'error_text' => $message->getResponseError(),
  321.                 'measuring_point' => self::MEASURING_POINT_SOAP_RESPONSE,
  322.             ]
  323.         );
  324.     }
  325.     /**
  326.      * Determines the SOAP operation, which is to be called.
  327.      *
  328.      * Returns an empty string if no operation could be determined.
  329.      *
  330.      * @param AbstractMessage $message
  331.      *
  332.      * @return string
  333.      */
  334.     protected function determineOperation(AbstractMessage $message)
  335.     {
  336.         return $this->getSettingForMessage($message'webservice_operation');
  337.     }
  338.     /**
  339.      * Replace $ Syntax for config resolver placeholders.
  340.      *
  341.      * @param AbstractMessage $message
  342.      *
  343.      * @return mixed|null
  344.      */
  345.     protected function determineWebserviceUrl(AbstractMessage $message)
  346.     {
  347.         $webserviceUrl $this->getSettingForMessage($message'webservice_url');
  348.         if (strpos($webserviceUrl'$') !== false) {
  349.             $webserviceUrl str_replace('$web_connector.service_location;siso_erp$'$this->serviceLocation$webserviceUrl);
  350.         }
  351.         return $webserviceUrl;
  352.     }
  353.     /**
  354.      * Determines the identifier, which is used in the determine the respective
  355.      * mapping definition.
  356.      *
  357.      * E.g. In case of the XSL mapping it is the filename. The pattern would
  358.      * be: request|response.<identifer>.xsl
  359.      *
  360.      * Returns an empty string, if no identifier could be determined.
  361.      *
  362.      * @param AbstractMessage $message
  363.      *
  364.      * @return string
  365.      */
  366.     protected function determineMappingIdentifier(AbstractMessage $message)
  367.     {
  368.         return $this->getSettingForMessage($message'mapping_identifier');
  369.     }
  370.     /**
  371.      * Returns a setting for a message.
  372.      *
  373.      * @param AbstractMessage $message
  374.      * @param string $setting
  375.      *
  376.      * @return mixed|null
  377.      */
  378.     protected function getSettingForMessage(AbstractMessage $message$setting)
  379.     {
  380.         foreach ($this->messageSettings as $settings) {
  381.             if (isset($settings[$setting]) && get_class($message) === $settings['message_class']) {
  382.                 return $settings[$setting];
  383.             }
  384.         }
  385.         return null;
  386.     }
  387.     /**
  388.      * Determines the response document's class and instantiates it.
  389.      *
  390.      * @param AbstractMessage $message
  391.      *
  392.      * @throws ConfigurationException
  393.      *
  394.      * @return object
  395.      */
  396.     protected function determineResponseDocument(AbstractMessage $message)
  397.     {
  398.         $document null;
  399.         foreach ($this->messageSettings as $messageIdentifier => $settings) {
  400.             if (get_class($message) === $settings['message_class']) {
  401.                 $className $settings['response_document_class'];
  402.                 if (!class_exists($className)) {
  403.                     $exceptionMessage 'Given response_document_class for message "' $messageIdentifier '" does '
  404.                         'not exist: ' $className;
  405.                     throw new ConfigurationException($exceptionMessage);
  406.                 }
  407.                 $document = new $className();
  408.             }
  409.         }
  410.         if ($document === null) {
  411.             $exceptionMessage 'Response document could not be determined properly for message "' get_class($message)
  412.                 . '". Probably it is missing or wrong configured.';
  413.             throw new ConfigurationException($exceptionMessage);
  414.         }
  415.         return $document;
  416.     }
  417.     /**
  418.      * Invokes the request using PHP's SoapClient class.
  419.      *
  420.      * @param string $operation
  421.      * @param array $parameters
  422.      * @param array $clientParameters
  423.      * @param string $wsdl
  424.      *
  425.      * @return mixed|null
  426.      */
  427.     protected function invokeSoapRequest(
  428.         $operation,
  429.         array $parameters,
  430.         array $clientParameters = [],
  431.         $wsdl null
  432.     ) {
  433.         if (isset($parameters['data']['Params'])) {
  434.             $soapParameters $parameters['data']['Params'];
  435.         } elseif (isset($parameters['data']['params'])) {
  436.             $soapParameters $parameters['data']['params'];
  437.         }
  438.         if ($this->allowSelfSigned) {
  439.             $context stream_context_create(
  440.                 [
  441.                     'ssl' => [
  442.                         // set some SSL/TLS specific options
  443.                         'verify_peer' => false,
  444.                         'verify_peer_name' => false,
  445.                         'allow_self_signed' => true,
  446.                     ],
  447.                 ]
  448.             );
  449.             $clientParameters['stream_context'] = $context;
  450.         }
  451.         $clientParameters['trace'] = true;
  452.         $clientParameters['soap_version'] = SOAP_1_2;
  453.         $soapClient = new \SoapClient($wsdl$clientParameters);
  454.         $actionHeader $this->getWsdlActionHeader($wsdl$operation);
  455.         /* $actionHeader = new \SoapHeader('http://www.w3.org/2005/08/addressing',
  456.             'Action',
  457.             'http://tempuri.org/CustomerIISWebService/CustomerIISWebService/Read');*/
  458.         $soapClient->__setSoapHeaders($actionHeader);
  459.         try {
  460.             $erpResponse $soapClient->__soapCall($operation$soapParameters);
  461.             $response = [
  462.                 'status' => [
  463.                     'code' => ($erpResponse instanceof \StdClass) ? 1,
  464.                     'erp_status' => ($erpResponse instanceof \StdClass) ? 1,
  465.                 ],
  466.                 'SoapResponse' => $this->objectVarsToArray($erpResponse),
  467.             ];
  468.         } catch (\SoapFault $soapFault) {
  469.             // Try to get more information about the connection via cURL
  470.             $curlHandle curl_init($wsdl ?: $clientParameters['location']);
  471.             if ($this->allowSelfSigned) {
  472.                 curl_setopt($curlHandleCURLOPT_SSL_VERIFYPEERfalse);
  473.                 curl_setopt($curlHandleCURLOPT_SSL_VERIFYHOSTfalse);
  474.             }
  475.             curl_setopt($curlHandleCURLOPT_RETURNTRANSFERfalse);
  476.             curl_exec($curlHandle);
  477.             $errorMessage 'Error during SOAP communication:' PHP_EOL print_r(
  478.                     [
  479.                         'request' => $soapClient->__getLastRequest(),
  480.                         'requestHeaders' => $soapClient->__getLastRequestHeaders(),
  481.                         'response' => $soapClient->__getLastResponse(),
  482.                         'responseHeaders' => $soapClient->__getLastResponseHeaders(),
  483.                     ],
  484.                     true
  485.                 );
  486.             $context = [
  487.                 'exception' => $soapFault,
  488.                 'fault_code' => isset($soapFault->faultcode) ? $soapFault->faultcode '',
  489.                 'fault_text' => isset($soapFault->faultstring) ? $soapFault->faultstring '',
  490.                 'curl_errno' => curl_errno($curlHandle),
  491.                 'curl_error' => curl_error($curlHandle),
  492.             ];
  493.             curl_close($curlHandle);
  494.             $this->logging->error($errorMessage$context);
  495.             $response = [
  496.                 'status' => [
  497.                     'code' => $context['fault_code'],
  498.                 ],
  499.                 'error' => $context['fault_text'],
  500.             ];
  501.         }
  502.         return $response;
  503.     }
  504.     /**
  505.      * Converts objt to array.
  506.      *
  507.      * @param $object
  508.      *
  509.      * @return array
  510.      */
  511.     protected function objectVarsToArray($object)
  512.     {
  513.         if (is_array($object)) {
  514.             $object_vars $object;
  515.         } elseif (is_object($object)) {
  516.             $object_vars get_object_vars($object);
  517.         } else {
  518.             return [];
  519.         }
  520.         $var_array = [];
  521.         foreach ($object_vars as $var_name => $var_value) {
  522.             if (is_object($var_value) || is_array($var_value)) {
  523.                 $var_value $this->objectVarsToArray($var_value);
  524.             }
  525.             $var_array[$var_name] = $var_value;
  526.         }
  527.         return $var_array;
  528.     }
  529.     /** Checks WSDL for action parameters.
  530.      *
  531.      *  @param string $wsdl
  532.      *  @param string $operationName
  533.      *
  534.      *  @return array|bool
  535.      */
  536.     protected function getWsdlActionHeader($wsdl$operationName)
  537.     {
  538.         $arrContextOptions = [
  539.             'ssl' => [
  540.                 'verify_peer' => false,
  541.                 'verify_peer_name' => false,
  542.             ],
  543.         ];
  544.         $wsdlContent file_get_contents($wsdlfalsestream_context_create($arrContextOptions));
  545.         $doc = new \DOMDocument();
  546.         $doc->loadXML($wsdlContent);
  547.         $xpath = new \DOMXPath($doc);
  548.         $xpath->registerNamespace('soap12''http://schemas.xmlsoap.org/wsdl/soap12/');
  549.         $xpath->registerNamespace('wsdl''http://schemas.xmlsoap.org/wsdl/');
  550.         $query '//child::wsdl:operation[@name = "' $operationName '"]/soap12:operation/@soapAction';
  551.         $node_list $xpath->query($query);
  552.         if ($node_list->length 0) {
  553.             /** @var DOMAttr $first_node */
  554.             $first_node $node_list->item(0);
  555.             $actionHeader = new \SoapHeader(
  556.                 'http://www.w3.org/2005/08/addressing',
  557.                 'Action',
  558.                 $first_node->value
  559.             );
  560.             return $actionHeader;
  561.         }
  562.         return false;
  563.     }
  564.     /**
  565.      * Injects the mapping service.
  566.      *
  567.      * @param AbstractDocumentMappingService $mappingService
  568.      */
  569.     public function setMappingService(
  570.         AbstractDocumentMappingService $mappingService
  571.     ) {
  572.         $this->mappingService $mappingService;
  573.     }
  574.     /**
  575.      * Injects the local path or URL to the WSDL file.
  576.      *
  577.      * @param string $wsdlLocation
  578.      */
  579.     public function setWsdlLocation($wsdlLocation)
  580.     {
  581.         $this->wsdlLocation $wsdlLocation;
  582.     }
  583.     /**
  584.      * Validates the status of the remote service's response. If a message
  585.      * object is give, its responseStatus member is set accordingly.
  586.      *
  587.      * @param array $status
  588.      * @param AbstractMessage $message
  589.      *
  590.      * @return bool True if status signals successful response.
  591.      */
  592.     private function validateResponseStatus($statusAbstractMessage $message null)
  593.     {
  594.         if ($message !== null) {
  595.             if (isset($status['code']) && $status['code'] === 'HTTP') {
  596.                 $message->setResponseStatus(AbstractMessage::RESPONSE_STATUS_CONNECTION_ERROR);
  597.                 return false;
  598.             } elseif (isset($status['code']) && $status['code'] === 'Server') {
  599.                 $message->setResponseStatus(AbstractMessage::RESPONSE_STATUS_SERVICE_ERROR);
  600.                 return false;
  601.             } elseif (isset($status['code']) && $status['code'] === '0') {
  602.                 $message->setResponseStatus(AbstractMessage::RESPONSE_STATUS_SERVICE_ERROR);
  603.                 return false;
  604.             } elseif (isset($status['code']) && $status['code'] == '2') {
  605.                 $message->setResponseStatus(AbstractMessage::RESPONSE_STATUS_ERP_ERROR);
  606.                 return false;
  607.             } elseif (
  608.                 isset($status['code']) && ($status['code'] == 0)
  609.                 && isset($status['erp_status']) && ($status['erp_status'] == 0)
  610.             ) {
  611.                 $message->setResponseStatus(AbstractMessage::RESPONSE_STATUS_OK);
  612.                 return true;
  613.             } else {
  614.                 $message->setResponseStatus(AbstractMessage::RESPONSE_STATUS_SERVICE_ERROR);
  615.                 return false;
  616.             }
  617.         } else {
  618.             return isset($status['code']) && ($status['code'] == 0)
  619.             && isset($status['erp_status']) && ($status['erp_status'] == 0);
  620.         }
  621.     }
  622.     /**
  623.      * This checks the availability of the ERP system using the Web-Connector's
  624.      * ERP-status operation.
  625.      *
  626.      * Parent's description:
  627.      * {@inheritdoc}
  628.      *
  629.      * @return bool
  630.      */
  631.     public function testCommunication(&$errorText '')
  632.     {
  633.         $soapClientParameters = [
  634.             'location' => $this->serviceLocation,
  635.             'uri' => $this->serviceUri $this->serviceUri self::DEFAULT_URI,
  636.         ];
  637.         $response $this->invokeSoapRequest(self::PING, [], $soapClientParameters);
  638.         if (isset($response['status']) && $this->validateResponseStatus($response['status'])) {
  639.             return true;
  640.         }
  641.         $errorText = isset($response['error']) ? $response['error'] : $errorText;
  642.         $errorText .= isset($response['erp_message']) ? ' [ERP: ' $response['erp_message'] . ']' '';
  643.         return false;
  644.     }
  645. }