| Current Path : /srv/web/sites/trentinoplant.it/httpdocs/vendor/magento/framework/Api/ |
| Current File : /srv/web/sites/trentinoplant.it/httpdocs/vendor/magento/framework/Api/DataObjectHelper.php |
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Framework\Api;
use Magento\Framework\Reflection\MethodsMap;
/**
* Service class allow populating object from array data
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class DataObjectHelper
{
/**
* @var ObjectFactory
*/
protected $objectFactory;
/**
* @var \Magento\Framework\Reflection\DataObjectProcessor
*/
protected $objectProcessor;
/**
* @var \Magento\Framework\Reflection\TypeProcessor
*/
protected $typeProcessor;
/**
* @var \Magento\Framework\Api\ExtensionAttributesFactory
*/
protected $extensionFactory;
/**
* @var \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface
*/
protected $joinProcessor;
/**
* @var MethodsMap
*/
protected $methodsMapProcessor;
/**
* @param ObjectFactory $objectFactory
* @param \Magento\Framework\Reflection\DataObjectProcessor $objectProcessor
* @param \Magento\Framework\Reflection\TypeProcessor $typeProcessor
* @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory
* @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $joinProcessor
* @param MethodsMap $methodsMapProcessor
*/
public function __construct(
ObjectFactory $objectFactory,
\Magento\Framework\Reflection\DataObjectProcessor $objectProcessor,
\Magento\Framework\Reflection\TypeProcessor $typeProcessor,
\Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
\Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $joinProcessor,
MethodsMap $methodsMapProcessor
) {
$this->objectFactory = $objectFactory;
$this->objectProcessor = $objectProcessor;
$this->typeProcessor = $typeProcessor;
$this->extensionFactory = $extensionFactory;
$this->joinProcessor = $joinProcessor;
$this->methodsMapProcessor = $methodsMapProcessor;
}
/**
* Populate data object using data in array format.
*
* @param mixed $dataObject
* @param array $data
* @param string $interfaceName
* @return $this
*/
public function populateWithArray($dataObject, array $data, $interfaceName)
{
if ($dataObject instanceof ExtensibleDataInterface) {
$data = $this->joinProcessor->extractExtensionAttributes(get_class($dataObject), $data);
}
$this->_setDataValues($dataObject, $data, $interfaceName);
return $this;
}
/**
* Update Data Object with the data from array
*
* @param mixed $dataObject
* @param array $data
* @param string $interfaceName
* @return $this
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
protected function _setDataValues($dataObject, array $data, $interfaceName)
{
if (empty($data)) {
return $this;
}
$setMethods = $this->getSetters($dataObject);
$data = $this->setCustomAttributes(
$dataObject,
$data,
[
CustomAttributesDataInterface::CUSTOM_ATTRIBUTES,
CustomAttributesDataInterface::CUSTOM_ATTRIBUTES . "V2"
]
);
if ($dataObject instanceof \Magento\Framework\Model\AbstractModel) {
$simpleData = array_filter($data, static function ($e) {
return is_scalar($e) || is_null($e);
});
if (isset($simpleData['id'])) {
$dataObject->setId($simpleData['id']);
unset($simpleData['id']);
}
$simpleData = array_intersect_key($simpleData, $setMethods);
$dataObject->addData($simpleData);
$data = array_diff_key($data, $simpleData);
if (\count($data) === 0) {
return $this;
}
}
foreach (array_intersect_key($data, $setMethods) as $key => $value) {
$methodName = SimpleDataObjectConverter::snakeCaseToUpperCamelCase($key);
if (!is_array($value)) {
if ($methodName !== 'ExtensionAttributes' || $value !== null) {
if (method_exists($dataObject, 'set' . $methodName)) {
$dataObject->{'set' . $methodName}($value);
} else {
$dataObject->{'setIs' . $methodName}($value);
}
}
} else {
$getterMethodName = 'get' . $methodName;
$this->setComplexValue($dataObject, $getterMethodName, 'set' . $methodName, $value, $interfaceName);
}
unset($data[$key]);
}
if ($dataObject instanceof CustomAttributesDataInterface) {
foreach ($data as $key => $value) {
$dataObject->setCustomAttribute($key, $value);
}
}
return $this;
}
/**
* Set complex (like object) value using $methodName based on return type of $getterMethodName
*
* @param mixed $dataObject
* @param string $getterMethodName
* @param string $methodName
* @param array $value
* @param string $interfaceName
* @return $this
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function setComplexValue(
$dataObject,
$getterMethodName,
$methodName,
array $value,
$interfaceName
) {
if ($interfaceName == null) {
$interfaceName = get_class($dataObject);
}
$returnType = $this->methodsMapProcessor->getMethodReturnType($interfaceName, $getterMethodName);
if ($this->typeProcessor->isTypeSimple($returnType)) {
$dataObject->$methodName($value);
return $this;
}
if ($this->typeProcessor->isArrayType($returnType)) {
$type = $this->typeProcessor->getArrayItemType($returnType);
$objects = [];
foreach ($value as $arrayElementData) {
$object = $this->objectFactory->create($type, []);
$this->populateWithArray($object, $arrayElementData, $type);
$objects[] = $object;
}
$dataObject->$methodName($objects);
return $this;
}
if (is_subclass_of($returnType, \Magento\Framework\Api\ExtensibleDataInterface::class)) {
$object = $this->objectFactory->create($returnType, []);
$this->populateWithArray($object, $value, $returnType);
} elseif (is_subclass_of($returnType, \Magento\Framework\Api\ExtensionAttributesInterface::class)) {
foreach ($value as $extensionAttributeKey => $extensionAttributeValue) {
$extensionAttributeGetterMethodName
= 'get' . SimpleDataObjectConverter::snakeCaseToUpperCamelCase(
$extensionAttributeKey
);
$methodReturnType = $this->methodsMapProcessor->getMethodReturnType(
$returnType,
$extensionAttributeGetterMethodName
);
$extensionAttributeType = $this->typeProcessor->isArrayType($methodReturnType)
? $this->typeProcessor->getArrayItemType($methodReturnType)
: $methodReturnType;
if ($this->typeProcessor->isTypeSimple($extensionAttributeType)) {
$value[$extensionAttributeKey] = $extensionAttributeValue;
} else {
if ($this->typeProcessor->isArrayType($methodReturnType)) {
foreach ($extensionAttributeValue as $key => $extensionAttributeArrayValue) {
$extensionAttribute = $this->objectFactory->create($extensionAttributeType, []);
$this->populateWithArray(
$extensionAttribute,
$extensionAttributeArrayValue,
$extensionAttributeType
);
$value[$extensionAttributeKey][$key] = $extensionAttribute;
}
} else {
$value[$extensionAttributeKey] = $this->objectFactory->create(
$extensionAttributeType,
['data' => $extensionAttributeValue]
);
}
}
}
$object = $this->extensionFactory->create(get_class($dataObject), ['data' => $value]);
} else {
$object = $this->objectFactory->create($returnType, $value);
}
$dataObject->$methodName($object);
return $this;
}
/**
* Merges second object onto the first
*
* @param string $interfaceName
* @param mixed $firstDataObject
* @param mixed $secondDataObject
* @return $this
* @throws \LogicException
*/
public function mergeDataObjects(
$interfaceName,
$firstDataObject,
$secondDataObject
) {
if (!$firstDataObject instanceof $interfaceName || !$secondDataObject instanceof $interfaceName) {
throw new \LogicException('Wrong prototype object given. It can only be of "' . $interfaceName . '" type.');
}
$secondObjectArray = $this->objectProcessor->buildOutputDataArray($secondDataObject, $interfaceName);
$this->_setDataValues($firstDataObject, $secondObjectArray, $interfaceName);
return $this;
}
/**
* Filter attribute value objects for a provided data interface type from an array of custom attribute value objects
*
* @param AttributeValue[] $attributeValues Array of custom attribute
* @param string $type Data interface type
* @return AttributeValue[]
*/
public function getCustomAttributeValueByType(array $attributeValues, $type)
{
$attributeValueArray = [];
if (empty($attributeValues)) {
return $attributeValueArray;
}
foreach ($attributeValues as $attributeValue) {
if ($attributeValue->getValue() instanceof $type) {
$attributeValueArray[] = $attributeValue;
}
}
return $attributeValueArray;
}
/** @var array */
private array $settersCache = [];
/**
* Get list of setters for object
*
* @param object $dataObject
* @return array
*/
private function getSetters(object $dataObject): array
{
$class = get_class($dataObject);
if (!isset($this->settersCache[$class])) {
$dataObjectMethods = get_class_methods($class);
// use regexp to manipulate with method list as it use jit starting with PHP 7.3
$setters = array_filter(
explode(
',',
strtolower(
// (0) remove all not setter
// (1) add _ before upper letter
// (2) remove set_ in start of name
// (3) add name without is_ prefix
preg_replace(
['/(^|,)(?!set)[^,]*/S','/([A-Z])/S', '/(^|,)set_/iS', '/(^|,)is_([^,]+)/is'],
['', '_$1', '$1', '$1$2,is_$2'],
implode(',', $dataObjectMethods)
)
)
)
);
$this->settersCache[$class] = array_flip($setters);
}
return $this->settersCache[$class];
}
/**
* Set custom attributes using the $attributeKeys parameter.
*
* @param mixed $dataObject
* @param array $data
* @param array $attributeKeys
* @return array
*/
public function setCustomAttributes(mixed $dataObject, array $data, array $attributeKeys): array
{
foreach ($attributeKeys as $attributeKey) {
if ($dataObject instanceof ExtensibleDataInterface
&& !empty($data[$attributeKey])
) {
foreach ($data[$attributeKey] as $customAttribute) {
$dataObject->setCustomAttribute(
$customAttribute[AttributeInterface::ATTRIBUTE_CODE],
$customAttribute[AttributeInterface::VALUE]
);
}
unset($data[$attributeKey]);
}
}
return $data;
}
}