ExtensionAttributesProcessor.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Reflection;
  7. use Magento\Framework\Api\ExtensionAttribute\Config;
  8. use Magento\Framework\Api\ExtensionAttribute\Config\Converter;
  9. use Magento\Framework\AuthorizationInterface;
  10. use Magento\Framework\Phrase;
  11. use Magento\Framework\Api\ExtensionAttributesInterface;
  12. use Zend\Code\Reflection\MethodReflection;
  13. /**
  14. * Processes extension attributes and produces an array for the data.
  15. *
  16. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  17. */
  18. class ExtensionAttributesProcessor
  19. {
  20. /**
  21. * @var DataObjectProcessor
  22. */
  23. private $dataObjectProcessor;
  24. /**
  25. * @var MethodsMap
  26. */
  27. private $methodsMapProcessor;
  28. /**
  29. * @var AuthorizationInterface
  30. */
  31. private $authorization;
  32. /**
  33. * @var Config
  34. */
  35. private $config;
  36. /**
  37. * @var bool
  38. */
  39. private $isPermissionChecked;
  40. /**
  41. * @var FieldNamer
  42. */
  43. private $fieldNamer;
  44. /**
  45. * @var TypeCaster
  46. */
  47. private $typeCaster;
  48. /**
  49. * @param DataObjectProcessor $dataObjectProcessor
  50. * @param MethodsMap $methodsMapProcessor
  51. * @param TypeCaster $typeCaster
  52. * @param FieldNamer $fieldNamer
  53. * @param AuthorizationInterface $authorization
  54. * @param Config $config
  55. * @param bool $isPermissionChecked
  56. */
  57. public function __construct(
  58. DataObjectProcessor $dataObjectProcessor,
  59. MethodsMap $methodsMapProcessor,
  60. TypeCaster $typeCaster,
  61. FieldNamer $fieldNamer,
  62. AuthorizationInterface $authorization,
  63. Config $config,
  64. $isPermissionChecked = false
  65. ) {
  66. $this->dataObjectProcessor = $dataObjectProcessor;
  67. $this->methodsMapProcessor = $methodsMapProcessor;
  68. $this->typeCaster = $typeCaster;
  69. $this->fieldNamer = $fieldNamer;
  70. $this->authorization = $authorization;
  71. $this->config = $config;
  72. $this->isPermissionChecked = $isPermissionChecked;
  73. }
  74. /**
  75. * Writes out the extension attributes in an array.
  76. *
  77. * @param ExtensionAttributeInterface $dataObject
  78. * @param string $dataObjectType
  79. * @return array
  80. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  81. */
  82. public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $dataObjectType)
  83. {
  84. $methods = $this->methodsMapProcessor->getMethodsMap($dataObjectType);
  85. $outputData = [];
  86. /** @var MethodReflection $method */
  87. foreach (array_keys($methods) as $methodName) {
  88. if (!$this->methodsMapProcessor->isMethodValidForDataField($dataObjectType, $methodName)) {
  89. continue;
  90. }
  91. $key = $this->fieldNamer->getFieldNameForMethodName($methodName);
  92. if ($this->isPermissionChecked && !$this->isAttributePermissionValid($dataObjectType, $key)) {
  93. continue;
  94. }
  95. $value = $dataObject->{$methodName}();
  96. if ($value === null) {
  97. // all extension attributes are optional so don't need to check if isRequired
  98. continue;
  99. }
  100. $returnType = $this->methodsMapProcessor->getMethodReturnType($dataObjectType, $methodName);
  101. if (is_object($value) && !($value instanceof Phrase)) {
  102. $value = $this->dataObjectProcessor->buildOutputDataArray($value, $returnType);
  103. } elseif (is_array($value)) {
  104. $valueResult = [];
  105. $arrayElementType = substr($returnType, 0, -2);
  106. foreach ($value as $singleValue) {
  107. if (is_object($singleValue) && !($singleValue instanceof Phrase)) {
  108. $singleValue = $this->dataObjectProcessor->buildOutputDataArray(
  109. $singleValue,
  110. $arrayElementType
  111. );
  112. }
  113. $valueResult[] = $this->typeCaster->castValueToType($singleValue, $arrayElementType);
  114. }
  115. $value = $valueResult;
  116. } else {
  117. $value = $this->typeCaster->castValueToType($value, $returnType);
  118. }
  119. $outputData[$key] = $value;
  120. }
  121. return $outputData;
  122. }
  123. /**
  124. * @param string $dataObjectType
  125. * @param string $attributeCode
  126. * @return bool
  127. */
  128. private function isAttributePermissionValid($dataObjectType, $attributeCode)
  129. {
  130. $typeName = $this->getRegularTypeForExtensionAttributesType($dataObjectType);
  131. $permissions = $this->getPermissionsForTypeAndMethod($typeName, $attributeCode);
  132. foreach ($permissions as $permission) {
  133. if (!$this->authorization->isAllowed($permission)) {
  134. return false;
  135. }
  136. }
  137. return true;
  138. }
  139. /**
  140. * @param string $name
  141. * @return string
  142. */
  143. private function getRegularTypeForExtensionAttributesType($name)
  144. {
  145. return ltrim(str_replace('ExtensionInterface', 'Interface', $name), '\\');
  146. }
  147. /**
  148. * @param string $typeName
  149. * @param string $attributeCode
  150. * @return string[] A list of permissions
  151. */
  152. private function getPermissionsForTypeAndMethod($typeName, $attributeCode)
  153. {
  154. $attributes = $this->config->get();
  155. if (isset($attributes[$typeName]) && isset($attributes[$typeName][$attributeCode])) {
  156. $attributeMetadata = $attributes[$typeName][$attributeCode];
  157. $permissions = [];
  158. foreach ($attributeMetadata[Converter::RESOURCE_PERMISSIONS] as $permission) {
  159. $permissions[] = $permission;
  160. }
  161. return $permissions;
  162. }
  163. return [];
  164. }
  165. }