Form.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Customer\Model\Metadata;
  7. use Magento\Customer\Api\AddressMetadataInterface;
  8. use Magento\Customer\Api\CustomerMetadataInterface;
  9. /**
  10. * @api
  11. * @since 100.0.2
  12. */
  13. class Form
  14. {
  15. /**#@+
  16. * Values for ignoreInvisible parameter in constructor
  17. */
  18. const IGNORE_INVISIBLE = true;
  19. const DONT_IGNORE_INVISIBLE = false;
  20. /**#@-*/
  21. /**#@-*/
  22. protected $_customerMetadataService;
  23. /**
  24. * @var AddressMetadataInterface
  25. */
  26. protected $_addressMetadataService;
  27. /**
  28. * @var ElementFactory
  29. */
  30. protected $_elementFactory;
  31. /**
  32. * @var string
  33. */
  34. protected $_entityType;
  35. /**
  36. * @var string
  37. */
  38. protected $_formCode;
  39. /**
  40. * @var bool
  41. */
  42. protected $_ignoreInvisible = true;
  43. /**
  44. * @var array
  45. */
  46. protected $_filterAttributes = [];
  47. /**
  48. * @var bool
  49. */
  50. protected $_isAjax = false;
  51. /**
  52. * Attribute values
  53. *
  54. * @var array
  55. */
  56. protected $_attributeValues = [];
  57. /**
  58. * @var \Magento\Framework\App\RequestInterface
  59. */
  60. protected $_httpRequest;
  61. /**
  62. * @var \Magento\Framework\Module\Dir\Reader
  63. */
  64. protected $_modulesReader;
  65. /**
  66. * @var \Magento\Framework\Validator\ConfigFactory
  67. */
  68. protected $_validatorConfigFactory;
  69. /**
  70. * @var \Magento\Framework\Validator
  71. */
  72. protected $_validator;
  73. /**
  74. * @var \Magento\Customer\Api\Data\AttributeMetadataInterface[]
  75. */
  76. protected $_attributes;
  77. /**
  78. * @param CustomerMetadataInterface $customerMetadataService
  79. * @param AddressMetadataInterface $addressMetadataService
  80. * @param ElementFactory $elementFactory
  81. * @param \Magento\Framework\App\RequestInterface $httpRequest
  82. * @param \Magento\Framework\Module\Dir\Reader $modulesReader
  83. * @param \Magento\Framework\Validator\ConfigFactory $validatorConfigFactory
  84. * @param string $entityType
  85. * @param string $formCode
  86. * @param array $attributeValues
  87. * @param bool $ignoreInvisible
  88. * @param array $filterAttributes
  89. * @param bool $isAjax
  90. *
  91. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  92. */
  93. public function __construct(
  94. CustomerMetadataInterface $customerMetadataService,
  95. AddressMetadataInterface $addressMetadataService,
  96. ElementFactory $elementFactory,
  97. \Magento\Framework\App\RequestInterface $httpRequest,
  98. \Magento\Framework\Module\Dir\Reader $modulesReader,
  99. \Magento\Framework\Validator\ConfigFactory $validatorConfigFactory,
  100. $entityType,
  101. $formCode,
  102. array $attributeValues = [],
  103. $ignoreInvisible = self::IGNORE_INVISIBLE,
  104. $filterAttributes = [],
  105. $isAjax = false
  106. ) {
  107. $this->_customerMetadataService = $customerMetadataService;
  108. $this->_addressMetadataService = $addressMetadataService;
  109. $this->_elementFactory = $elementFactory;
  110. $this->_attributeValues = $attributeValues;
  111. $this->_entityType = $entityType;
  112. $this->_formCode = $formCode;
  113. $this->_ignoreInvisible = $ignoreInvisible;
  114. $this->_filterAttributes = $filterAttributes;
  115. $this->_isAjax = $isAjax;
  116. $this->_httpRequest = $httpRequest;
  117. $this->_modulesReader = $modulesReader;
  118. $this->_validatorConfigFactory = $validatorConfigFactory;
  119. }
  120. /**
  121. * Retrieve attributes metadata for the form
  122. *
  123. * @return \Magento\Customer\Api\Data\AttributeMetadataInterface[]
  124. * @throws \LogicException For undefined entity type
  125. */
  126. public function getAttributes()
  127. {
  128. if (!isset($this->_attributes)) {
  129. if ($this->_entityType === \Magento\Customer\Api\CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER) {
  130. $this->_attributes = $this->_customerMetadataService->getAttributes($this->_formCode);
  131. } elseif ($this->_entityType === \Magento\Customer\Api\AddressMetadataInterface::ENTITY_TYPE_ADDRESS) {
  132. $this->_attributes = $this->_addressMetadataService->getAttributes($this->_formCode);
  133. } else {
  134. throw new \LogicException('Undefined entity type: ' . $this->_entityType);
  135. }
  136. }
  137. return $this->_attributes;
  138. }
  139. /**
  140. * Return attribute instance by code or false
  141. *
  142. * @param string $attributeCode
  143. * @return \Magento\Customer\Api\Data\AttributeMetadataInterface|false
  144. */
  145. public function getAttribute($attributeCode)
  146. {
  147. $attributes = $this->getAttributes();
  148. if (isset($attributes[$attributeCode])) {
  149. return $attributes[$attributeCode];
  150. }
  151. return false;
  152. }
  153. /**
  154. * Retrieve user defined attributes
  155. *
  156. * @return \Magento\Customer\Api\Data\AttributeMetadataInterface[]
  157. */
  158. public function getUserAttributes()
  159. {
  160. $result = [];
  161. foreach ($this->getAttributes() as $attribute) {
  162. if ($attribute->isUserDefined()) {
  163. $result[$attribute->getAttributeCode()] = $attribute;
  164. }
  165. }
  166. return $result;
  167. }
  168. /**
  169. * Retrieve system required attributes
  170. *
  171. * @return \Magento\Customer\Api\Data\AttributeMetadataInterface[]
  172. */
  173. public function getSystemAttributes()
  174. {
  175. $result = [];
  176. foreach ($this->getAttributes() as $attribute) {
  177. if (!$attribute->isUserDefined()) {
  178. $result[$attribute->getAttributeCode()] = $attribute;
  179. }
  180. }
  181. return $result;
  182. }
  183. /**
  184. * Retrieve filtered attributes
  185. *
  186. * @return \Magento\Customer\Api\Data\AttributeMetadataInterface[]
  187. */
  188. public function getAllowedAttributes()
  189. {
  190. $attributes = $this->getAttributes();
  191. foreach ($attributes as $attributeCode => $attribute) {
  192. if ($this->_ignoreInvisible && !$attribute->isVisible() || in_array(
  193. $attribute->getAttributeCode(),
  194. $this->_filterAttributes
  195. )
  196. ) {
  197. unset($attributes[$attributeCode]);
  198. }
  199. }
  200. return $attributes;
  201. }
  202. /**
  203. * Extract data from request and return associative data array
  204. *
  205. * @param \Magento\Framework\App\RequestInterface $request
  206. * @param string $scope the request scope
  207. * @param boolean $scopeOnly search value only in scope or search value in global too
  208. * @return array
  209. */
  210. public function extractData(\Magento\Framework\App\RequestInterface $request, $scope = null, $scopeOnly = true)
  211. {
  212. $data = [];
  213. foreach ($this->getAllowedAttributes() as $attribute) {
  214. $dataModel = $this->_getAttributeDataModel($attribute);
  215. $dataModel->setRequestScope($scope);
  216. $dataModel->setRequestScopeOnly($scopeOnly);
  217. $data[$attribute->getAttributeCode()] = $dataModel->extractValue($request);
  218. }
  219. return $data;
  220. }
  221. /**
  222. * Compact data array to form attribute values
  223. *
  224. * @param array $data
  225. * @return array attribute values
  226. */
  227. public function compactData(array $data)
  228. {
  229. foreach ($this->getAllowedAttributes() as $attribute) {
  230. $dataModel = $this->_getAttributeDataModel($attribute);
  231. $dataModel->setExtractedData($data);
  232. if (!isset($data[$attribute->getAttributeCode()])) {
  233. $data[$attribute->getAttributeCode()] = false;
  234. }
  235. $attributeCode = $attribute->getAttributeCode();
  236. $this->_attributeValues[$attributeCode] = $dataModel->compactValue($data[$attributeCode]);
  237. }
  238. return $this->_attributeValues;
  239. }
  240. /**
  241. * Restore data array from SESSION to attribute values
  242. *
  243. * @param array $data
  244. * @return array
  245. */
  246. public function restoreData(array $data)
  247. {
  248. foreach ($this->getAllowedAttributes() as $attribute) {
  249. $dataModel = $this->_getAttributeDataModel($attribute);
  250. $dataModel->setExtractedData($data);
  251. if (!isset($data[$attribute->getAttributeCode()])) {
  252. $data[$attribute->getAttributeCode()] = false;
  253. }
  254. $attributeCode = $attribute->getAttributeCode();
  255. $this->_attributeValues[$attributeCode] = $dataModel->restoreValue($data[$attributeCode]);
  256. }
  257. return $this->_attributeValues;
  258. }
  259. /**
  260. * Return attribute data model by attribute
  261. *
  262. * @param \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute
  263. * @return \Magento\Eav\Model\Attribute\Data\AbstractData
  264. */
  265. protected function _getAttributeDataModel($attribute)
  266. {
  267. $dataModel = $this->_elementFactory->create(
  268. $attribute,
  269. isset(
  270. $this->_attributeValues[$attribute->getAttributeCode()]
  271. ) ? $this->_attributeValues[$attribute->getAttributeCode()] : null,
  272. $this->_entityType,
  273. $this->_isAjax
  274. );
  275. return $dataModel;
  276. }
  277. /**
  278. * Prepare request with data and returns it
  279. *
  280. * @param array $data
  281. * @return \Magento\Framework\App\RequestInterface
  282. */
  283. public function prepareRequest(array $data)
  284. {
  285. $request = clone $this->_httpRequest;
  286. $request->clearParams();
  287. $request->setParams($data);
  288. return $request;
  289. }
  290. /**
  291. * Get validator
  292. *
  293. * @param array $data
  294. * @return \Magento\Framework\Validator
  295. */
  296. protected function _getValidator(array $data)
  297. {
  298. if ($this->_validator !== null) {
  299. return $this->_validator;
  300. }
  301. $configFiles = $this->_modulesReader->getConfigurationFiles('validation.xml');
  302. $validatorFactory = $this->_validatorConfigFactory->create(['configFiles' => $configFiles]);
  303. $builder = $validatorFactory->createValidatorBuilder('customer', 'form');
  304. $builder->addConfiguration(
  305. 'metadata_data_validator',
  306. ['method' => 'setAttributes', 'arguments' => [$this->getAllowedAttributes()]]
  307. );
  308. $builder->addConfiguration(
  309. 'metadata_data_validator',
  310. ['method' => 'setData', 'arguments' => [$data]]
  311. );
  312. $builder->addConfiguration(
  313. 'metadata_data_validator',
  314. ['method' => 'setEntityType', 'arguments' => [$this->_entityType]]
  315. );
  316. $this->_validator = $builder->createValidator();
  317. return $this->_validator;
  318. }
  319. /**
  320. * Validate data array and return true or array of errors
  321. *
  322. * @param array $data
  323. * @return boolean|array
  324. */
  325. public function validateData(array $data)
  326. {
  327. $validator = $this->_getValidator($data);
  328. if (!$validator->isValid(false)) {
  329. $messages = [];
  330. foreach ($validator->getMessages() as $errorMessages) {
  331. $messages = array_merge($messages, (array)$errorMessages);
  332. }
  333. return $messages;
  334. }
  335. return true;
  336. }
  337. /**
  338. * Return array of formatted allowed attributes values.
  339. *
  340. * @param string $format
  341. * @return array
  342. */
  343. public function outputData($format = \Magento\Eav\Model\AttributeDataFactory::OUTPUT_FORMAT_TEXT)
  344. {
  345. $result = [];
  346. foreach ($this->getAllowedAttributes() as $attribute) {
  347. $dataModel = $this->_getAttributeDataModel($attribute);
  348. $result[$attribute->getAttributeCode()] = $dataModel->outputValue($format);
  349. }
  350. return $result;
  351. }
  352. /**
  353. * Set whether invisible attributes should be ignored.
  354. *
  355. * @param bool $ignoreInvisible
  356. * @return void
  357. */
  358. public function setInvisibleIgnored($ignoreInvisible)
  359. {
  360. $this->_ignoreInvisible = $ignoreInvisible;
  361. }
  362. }