mirror of
https://github.com/bdnugget/magento2.git
synced 2026-11-07 17:27:36 +00:00
311 lines
11 KiB
PHP
311 lines
11 KiB
PHP
<?php
|
|
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Magento\Webapi\Controller\Soap\Request;
|
|
|
|
use InvalidArgumentException;
|
|
use Magento\Framework\Api\ExtensibleDataInterface;
|
|
use Magento\Framework\Api\MetadataObjectInterface;
|
|
use Magento\Framework\Api\SimpleDataObjectConverter;
|
|
use Magento\Framework\App\Backpressure\BackpressureExceededException;
|
|
use Magento\Framework\App\BackpressureEnforcerInterface;
|
|
use Magento\Framework\App\ObjectManager;
|
|
use Magento\Framework\ObjectManagerInterface;
|
|
use Magento\Framework\Webapi\Authorization;
|
|
use Magento\Framework\Exception\AuthorizationException;
|
|
use Magento\Framework\Reflection\DataObjectProcessor;
|
|
use Magento\Framework\Webapi\Backpressure\BackpressureContextFactory;
|
|
use Magento\Framework\Webapi\ServiceInputProcessor;
|
|
use Magento\Framework\Webapi\Request as WebapiRequest;
|
|
use Magento\Framework\Webapi\Exception as WebapiException;
|
|
use Magento\Framework\Webapi\Validator\EntityArrayValidator\InputArraySizeLimitValue;
|
|
use Magento\Webapi\Controller\Rest\ParamsOverrider;
|
|
use Magento\Webapi\Model\Soap\Config as SoapConfig;
|
|
use Magento\Framework\Reflection\MethodsMap;
|
|
use Magento\Webapi\Model\ServiceMetadata;
|
|
|
|
/**
|
|
* Handler of requests to SOAP server
|
|
*
|
|
* The main responsibility is to instantiate proper action controller (service) and execute requested method on it
|
|
*
|
|
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
|
*/
|
|
class Handler
|
|
{
|
|
public const RESULT_NODE_NAME = 'result';
|
|
|
|
/**
|
|
* @var WebapiRequest
|
|
*/
|
|
protected $_request;
|
|
|
|
/**
|
|
* @var ObjectManagerInterface
|
|
*/
|
|
protected $_objectManager;
|
|
|
|
/**
|
|
* @var SoapConfig
|
|
*/
|
|
protected $_apiConfig;
|
|
|
|
/**
|
|
* @var Authorization
|
|
*/
|
|
protected $authorization;
|
|
|
|
/**
|
|
* @var SimpleDataObjectConverter
|
|
*/
|
|
protected $_dataObjectConverter;
|
|
|
|
/**
|
|
* @var ServiceInputProcessor
|
|
*/
|
|
protected $serviceInputProcessor;
|
|
|
|
/**
|
|
* @var DataObjectProcessor
|
|
*/
|
|
protected $_dataObjectProcessor;
|
|
|
|
/**
|
|
* @var MethodsMap
|
|
*/
|
|
protected $methodsMapProcessor;
|
|
|
|
/**
|
|
* @var ParamsOverrider
|
|
*/
|
|
private $paramsOverrider;
|
|
|
|
/**
|
|
* @var BackpressureContextFactory
|
|
*/
|
|
private BackpressureContextFactory $backpressureContextFactory;
|
|
|
|
/**
|
|
* @var BackpressureEnforcerInterface
|
|
*/
|
|
private BackpressureEnforcerInterface $backpressureEnforcer;
|
|
|
|
/**
|
|
* @var InputArraySizeLimitValue
|
|
*/
|
|
private $inputArraySizeLimitValue;
|
|
|
|
/**
|
|
* @param WebapiRequest $request
|
|
* @param ObjectManagerInterface $objectManager
|
|
* @param SoapConfig $apiConfig
|
|
* @param Authorization $authorization
|
|
* @param SimpleDataObjectConverter $dataObjectConverter
|
|
* @param ServiceInputProcessor $serviceInputProcessor
|
|
* @param DataObjectProcessor $dataObjectProcessor
|
|
* @param MethodsMap $methodsMapProcessor
|
|
* @param ParamsOverrider|null $paramsOverrider
|
|
* @param InputArraySizeLimitValue|null $inputArraySizeLimitValue
|
|
* @param BackpressureContextFactory|null $backpressureContextFactory
|
|
* @param BackpressureEnforcerInterface|null $backpressureEnforcer
|
|
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
|
|
*/
|
|
public function __construct(
|
|
WebapiRequest $request,
|
|
ObjectManagerInterface $objectManager,
|
|
SoapConfig $apiConfig,
|
|
Authorization $authorization,
|
|
SimpleDataObjectConverter $dataObjectConverter,
|
|
ServiceInputProcessor $serviceInputProcessor,
|
|
DataObjectProcessor $dataObjectProcessor,
|
|
MethodsMap $methodsMapProcessor,
|
|
?ParamsOverrider $paramsOverrider = null,
|
|
?InputArraySizeLimitValue $inputArraySizeLimitValue = null,
|
|
?BackpressureContextFactory $backpressureContextFactory = null,
|
|
?BackpressureEnforcerInterface $backpressureEnforcer = null
|
|
) {
|
|
$this->_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
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|