_request = $request; $this->_objectManager = $objectManager; $this->_apiConfig = $apiConfig; $this->authorization = $authorization; $this->_dataObjectConverter = $dataObjectConverter; $this->serviceInputProcessor = $serviceInputProcessor; $this->_dataObjectProcessor = $dataObjectProcessor; $this->methodsMapProcessor = $methodsMapProcessor; $this->paramsOverrider = $paramsOverrider ?? ObjectManager::getInstance()->get(ParamsOverrider::class); $this->inputArraySizeLimitValue = $inputArraySizeLimitValue ?? ObjectManager::getInstance()->get(InputArraySizeLimitValue::class); $this->backpressureContextFactory = $backpressureContextFactory ?? ObjectManager::getInstance()->get(BackpressureContextFactory::class); $this->backpressureEnforcer = $backpressureEnforcer ?? ObjectManager::getInstance()->get(BackpressureEnforcerInterface::class); } /** * Handler for all SOAP operations * * @param string $operation * @param array $arguments * @return array * @throws WebapiException * @throws \LogicException * @throws AuthorizationException * phpcs:disable Magento2.Functions.DiscouragedFunction * phpcs:disable Generic.PHP.NoSilencedErrors */ public function __call($operation, $arguments) { $requestedServices = $this->_request->getRequestedServices(); $serviceMethodInfo = $this->_apiConfig->getServiceMethodInfo($operation, $requestedServices); $serviceClass = $serviceMethodInfo[ServiceMetadata::KEY_CLASS]; $serviceMethod = $serviceMethodInfo[ServiceMetadata::KEY_METHOD]; // check if the operation is a secure operation & whether the request was made in HTTPS if ($serviceMethodInfo[ServiceMetadata::KEY_IS_SECURE] && !$this->_request->isSecure()) { throw new WebapiException(__("Operation allowed only in HTTPS")); } //Backpressure enforcement $this->backpressureEnforcement($serviceMethodInfo['class'], $serviceMethodInfo['method'], $operation); if (!$this->authorization->isAllowed($serviceMethodInfo[ServiceMetadata::KEY_ACL_RESOURCES])) { throw new AuthorizationException( __( "The consumer isn't authorized to access %resources.", ['resources' => implode(', ', $serviceMethodInfo[ServiceMetadata::KEY_ACL_RESOURCES])] ) ); } $service = $this->_objectManager->get($serviceClass); $inputData = $this->prepareOperationInput($serviceClass, $serviceMethodInfo, $arguments); $outputData = $this->runServiceMethod($service, $serviceMethod, $inputData); return $this->_prepareResponseData($outputData, $serviceClass, $serviceMethod); } /** * Runs service method * * @param object $service * @param string $serviceMethod * @param array $inputData * @return false|mixed */ private function runServiceMethod($service, $serviceMethod, $inputData) { // phpcs:ignore Magento2.Functions.DiscouragedFunction return call_user_func_array([$service, $serviceMethod], $inputData); } /** * Convert arguments received from SOAP server to arguments to pass to a service. * * @param string $serviceClass * @param array $methodMetadata * @param array $arguments * @return array * @throws WebapiException */ private function prepareOperationInput(string $serviceClass, array $methodMetadata, array $arguments): array { /** SoapServer wraps parameters into array. Thus this wrapping should be removed to get access to parameters. */ $arguments = reset($arguments); $arguments = $this->_dataObjectConverter->convertStdObjectToArray($arguments, true); $arguments = $this->paramsOverrider->override($arguments, $methodMetadata[ServiceMetadata::KEY_ROUTE_PARAMS]); $this->inputArraySizeLimitValue->set($methodMetadata[ServiceMetadata::KEY_INPUT_ARRAY_SIZE_LIMIT]); return $this->serviceInputProcessor->process( $serviceClass, $methodMetadata[ServiceMetadata::KEY_METHOD], $arguments ); } /** * Convert SOAP operation arguments into format acceptable by service method. * * @param string $serviceClass * @param string $serviceMethod * @param array $arguments * @return array * @throws WebapiException * @see Handler::prepareOperationInput() * @deprecated 100.3.2 */ protected function _prepareRequestData($serviceClass, $serviceMethod, $arguments) { return $this->prepareOperationInput( $serviceClass, [ServiceMetadata::KEY_METHOD => $serviceMethod, ServiceMetadata::KEY_ROUTE_PARAMS => []], $arguments ); } /** * Convert service response into format acceptable by SoapServer. * * @param object|array|string|int|float|null $data * @param string $serviceClassName * @param string $serviceMethodName * @return array * @throws InvalidArgumentException */ protected function _prepareResponseData($data, $serviceClassName, $serviceMethodName) { /** @var string $dataType */ $dataType = $this->methodsMapProcessor->getMethodReturnType($serviceClassName, $serviceMethodName); $result = null; if (is_object($data)) { $result = $this->_dataObjectConverter ->convertKeysToCamelCase($this->_dataObjectProcessor->buildOutputDataArray($data, $dataType)); } elseif (is_array($data)) { $dataType = substr((string)$dataType, 0, -2); foreach ($data as $key => $value) { if ($value instanceof $dataType // the following two options are supported for backward compatibility || $value instanceof ExtensibleDataInterface || $value instanceof MetadataObjectInterface ) { $result[] = $this->_dataObjectConverter ->convertKeysToCamelCase($this->_dataObjectProcessor->buildOutputDataArray($value, $dataType)); } else { $result[$key] = $value; } } } elseif (is_scalar($data) || $data === null) { $result = $data; } else { throw new InvalidArgumentException("Service returned result in invalid format."); } return [self::RESULT_NODE_NAME => $result]; } /** * Backpressure enforcement * * @param string $class * @param string $method * @param string $operation * @throws WebapiException */ private function backpressureEnforcement(string $class, string $method, string $operation) { $context = $this->backpressureContextFactory->create($class, $method, $operation); if ($context) { try { $this->backpressureEnforcer->enforce($context); } catch (BackpressureExceededException $exception) { throw new WebapiException( __('Too Many Requests'), 0, WebapiException::HTTP_TOO_MANY_REQUESTS ); } } } }